2017-01-05 2 views
1

Ich habe eine Tabelle mit Startdatum und die Häufigkeit des Berichts (alles 1 Monat, 2 Monaten etc .. Granularität ein Monat)nächstes Datum in der Zukunft von bestimmtem Zeitpunkt und Häufigkeit

Wie würde ich ein auswählen, die würde, für den tatsächlichen Tag, Rückkehrdatum des nächsten zukünftigen Berichts?

Example: 
startDate: 15.01.2015, frequency: 3 months 

if today is 03.01.2016 it should return 15.01.2016 
if today is 16.01.2016 it should return 15.04.2016 

Das Speichern des Datums des letzten Berichts ist keine Option.

Edit: Angeforderte Beispieldaten und erwartete Ergebnis:

Actual date is 05.01.2017 

StartDate Freq  Result 
02.01.2016 1month  02.02.2017 
06.01.2016 1month  06.01.2017 
10.03.2016 3months  10.03.2017 
01.01.2015 4months  01.05.2017 
+0

können Sie Beispieldaten zeigen, und – TheGameiswar

+0

@TheGameiswar Beispieldaten Ergebnis erwartet hinzugefügt, lassen Sie mich wissen, wenn es nicht genug ist – quin61

+0

Wie viele zukünftige Berichte? – McNets

Antwort

1

OK, lassen Sie spielen mit Mathe.

Berechnen Sie das nächste Auftreten eines Ereignisses, das jeden Monat von einem StartDate passiert?

Nun, zuerst berechne ich die remiander von Integer-Division und Modulo zwischen Monat nach Frequenz für alle Fälle MONAT (Startdatum) = MONAT (ActualDate)

StartDate - ActualDate % Frequency 

Dann muss ich wissen, wie oft hat holte den Bericht:

Occurrences = StartDate - ActualDate/Frequency 

Dann ein neues Auftreten hinzufügen und durch die Frequenz multiplizieren Sie die Anzahl der Monate bekommen Sie Startdatum, wobei darauf geachtet hinzufügen sollte, wenn TAG (Startdatum) < DAY (ActualDate).

(Occurrences + 1) * Frequency = Required month 

create table #t (StartDate datetime, Freq varchar(10)); 
insert into #t values 
('2016-01-02','1month'), 
('2016-01-06','1month'), 
('2016-03-10','3months'), 
('2015-01-01','4months'), 
('2016-01-06','3month'); 

DECLARE @ActualDate datetime; 
SET @ActualDate = '2017-01-05' 

SELECT @ActualDate as ActualDate; 

;WITH Calc AS 
(
    SELECT StartDate, Freq, CAST(LEFT(Freq, 1) AS Int) as intFreq, 
      (DATEDIFF(month, StartDate, @ActualDate)/CAST(LEFT(Freq, 1) AS Int)) AS Occurrences, 
      (DATEDIFF(month, StartDate, @ActualDate) % CAST(LEFT(Freq, 1) AS Int)) AS restIntDiv, 
      DATEPART(day, StartDate) AS StartDay, 
      DATEPART(day, @ActualDate) AS ActDay 
    FROM #t 
) 
SELECT StartDate, Freq, 
     CASE WHEN restIntDiv = 0 AND ActDay < StartDay 
      THEN DATEADD(month, intFreq * (Occurrences), StartDate) 
      ELSE DATEADD(month, intFreq * (Occurrences + 1), StartDate) 
     END as [NextReport] 
FROM Calc; 

+---------------------+---------+---------------------+ 
|  StartDate  | Freq | NextReport   | 
+---------------------+---------+---------------------+ 
| 02.01.2016 00:00:00 | 1month | 02.02.2017 00:00:00 | 
+---------------------+---------+---------------------+ 
| 06.01.2016 00:00:00 | 1month | 06.01.2017 00:00:00 | 
+---------------------+---------+---------------------+ 
| 10.03.2016 00:00:00 | 3months | 10.03.2017 00:00:00 | 
+---------------------+---------+---------------------+ 
| 01.01.2015 00:00:00 | 4months | 01.05.2017 00:00:00 | 
+---------------------+---------+---------------------+ 
| 06.01.2016 00:00:00 | 3month | 06.01.2017 00:00:00 | 
+---------------------+---------+---------------------+ 

Kann es hier ansehen: http://rextester.com/MBSM51925

+0

Es ist nicht klar, wie Ihre Antwort "StartDate" von der Frage berücksichtigt. – HABO

+0

Das ursprüngliche Problem ist: mit einem ** Startdatum ** vom 15. Januar 2015 und einem Intervall von drei Monaten, was das nächste Vorkommen nach dem aktuellen Datum sein wird. Ihr Code zeigt nicht an, ob das nächste Vorkommen im aktuellen Monat, nächsten Monat oder nachfolgenden Monat ist _basierend auf dem Startdatum_. Es ist unwahrscheinlich, dass heute drei Monate ab heute sind, es sei denn, heute ist der 15., und es ist ein Vielfaches von drei Monaten seit dem Startdatum. – HABO

+0

Ok, vielleicht kann es ohne eine cte durchgeführt werden, aber dieser Weg ist klarer .. – McNets

0

Ich benutze oft eine TVF dynamische Datums-/Zeitbereiche zu erstellen. Ein Tally-Tisch würde das auch tun. Die UDF ist schneller als ein rekursiver CTE (besonders für größere Mengen) und bietet ein bisschen mehr Funktionalität. Date Range, DatePart und Increments sind Parameter.

Declare @YourTable table (StartDate date,frequency varchar(25)) 
Insert Into @YourTable values 
('2016-01-02','1month'), 
('2016-01-06','1month'), 
('2016-03-10','3months'), 
('2015-01-01','4months') 

Select A.* 
     ,NextDate=cast(B.RetVal as date) 
From @YourTable A 
Cross Apply (
       Select Top 1 * From [dbo].[udf-Range-Date](A.StartDate,'2025-01-15','MM',left(A.frequency,1)) 
       Where RetVal>=cast(GetDate() as date) 
      ) B 

Returns

StartDate frequency NextDate 
2016-01-02 1month  2017-02-02 
2016-01-06 1month  2017-01-06 
2016-03-10 3months  2017-03-10 
2015-01-01 4months  2017-05-01 

Die UDF, wenn interessiert

CREATE FUNCTION [dbo].[udf-Range-Date] (@R1 datetime,@R2 datetime,@Part varchar(10),@Incr int) 
Returns Table 
Return (
    with cte0(M) As (Select 1+Case @Part When 'YY' then DateDiff(YY,@R1,@R2)/@Incr When 'QQ' then DateDiff(QQ,@R1,@R2)/@Incr When 'MM' then DateDiff(MM,@R1,@R2)/@Incr When 'WK' then DateDiff(WK,@R1,@R2)/@Incr When 'DD' then DateDiff(DD,@R1,@R2)/@Incr When 'HH' then DateDiff(HH,@R1,@R2)/@Incr When 'MI' then DateDiff(MI,@R1,@R2)/@Incr When 'SS' then DateDiff(SS,@R1,@R2)/@Incr End), 
     cte1(N) As (Select 1 From (Values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N(N)), 
     cte2(N) As (Select Top (Select M from cte0) Row_Number() over (Order By (Select NULL)) From cte1 a, cte1 b, cte1 c, cte1 d, cte1 e, cte1 f, cte1 g, cte1 h), 
     cte3(N,D) As (Select 0,@R1 Union All Select N,Case @Part When 'YY' then DateAdd(YY, N*@Incr, @R1) When 'QQ' then DateAdd(QQ, N*@Incr, @R1) When 'MM' then DateAdd(MM, N*@Incr, @R1) When 'WK' then DateAdd(WK, N*@Incr, @R1) When 'DD' then DateAdd(DD, N*@Incr, @R1) When 'HH' then DateAdd(HH, N*@Incr, @R1) When 'MI' then DateAdd(MI, N*@Incr, @R1) When 'SS' then DateAdd(SS, N*@Incr, @R1) End From cte2) 

    Select RetSeq = N+1 
      ,RetVal = D 
    From cte3,cte0 
    Where D<[email protected] 
) 
/* 
Max 100 million observations -- Date Parts YY QQ MM WK DD HH MI SS 
Syntax: 
Select * from [dbo].[udf-Range-Date]('2016-10-01','2020-10-01','YY',1) 
Select * from [dbo].[udf-Range-Date]('2016-01-01','2017-01-01','MM',1) 
*/ 
Verwandte Themen