2016-04-01 2 views
2

Ich möchte basierend auf dem Wochentag und der Nummer des Auftretens im Monat eines Datums eine Liste von Daten für jeden Monat zwischen zwei Daten generieren. Unter der Annahme, habe ich eine @StartDate = 2016/04/01 und @EndDate = 2016/09/01, ich überprüfen, ob @StartDate auf einem ersten Freitag im April, dann zu @EndDate wird Termine für alle ersten Freitag eines jeden Monats erstellen:Liste der Daten basierend auf dem Tag und dem Vorkommen des Monats erstellen

2016/05/06 
2016/06/03 
2016/07/01 
2016/08/05 

Bei @StartDate = 2016/04/12 und @EndDate = 2016/09/01 stelle ich fest, dass die @StartDate der zweite Dienstag im April ist, ging dann jeden zweiten Dienstag Dienstag jeden Monat zu erhalten:

2016/05/10 
2016/06/14 
2016/07/12 
2016/08/09 

bei @StartDate = 2016/04/28 und @EndDate = 2016/09/01 stellt ich fest, dass die @StartDate auf der l ast Donnerstag des Monats April:

2016/05/26 
2016/06/30 
2016/07/28 
2016/08/25 

Im letzten Fall, ich brauche die Anzahl der Wochen eines jeden Monats, um zu überprüfen, weil Monate gibt es nur bei 4 Wochen mit 5 Wochen, und ich möchte das letzte Vorkommen.

Was habe ich getan? Ich einen Code gefunden, der mich jeden Montag in der dritten Woche des Monats gibt, und ich nahm eine wenig ein @StartDate und @EndDate zu erhalten:

;with 
filler as (select row_number() over (order by a) a from (select top 100 1 as a from syscolumns) a cross join (select top 100 1 as b from syscolumns) b), 
dates as (select dateadd(month, a-1, @StartDate) date from filler where a <= 1000 and dateadd(month, a-1, @StartDate) < @EndDate), 
FirstMonday as (
select dateadd(day, case datepart(weekday,Date) /*this is the case where verify the week day*/ 
          when 1 then 1 
          when 2 then 0 
          when 3 then 6 
          when 4 then 5 
          when 5 then 4 
          when 6 then 3 
          when 7 then 2 
         end, Date) as Date 
     ,case when datepart(weekday, @StartDate) = 1 then 3 else 2 end as Weeks /*here i verify the number of weeks to sum in the next date*/ 
from dates 
) 
select dateadd(week, Weeks, Date) as ThirdMonday 
from FirstMonday 
+0

sind Ihre Regeln nicht eindeutig. Wie unterscheiden Sie zwischen dem vierten Montag eines Monats und dem letzten Montag? –

+0

@GordonLinoff Sie sprechen über den Code? Ich muss es anpassen, um dies zu tun – CesarMiguel

+1

Haben Sie in Betracht gezogen, eine [Kalendertabelle] (https://www.mssqltips.com/sqlservertip/4054/creating-a-date-dimension-or-calendar-table-in-sql -Server/)? Aus einer vollständigen Liste aller Daten, einschließlich Wochentage und Wochennummern, können Sie immer nur die gewünschten Daten filtern. –

Antwort

2

So ist es:

set @NumSemana = datepart(day, datediff(day, DATEADD(mm, DATEDIFF(mm,0,@StartDate), 0), @StartDate)/7 * 7)/7 + 1; 
WITH AllDays 
    AS (SELECT @StartDate AS [Date], DATEPART(month, @StartDate) as validMonth 
     UNION ALL 
     SELECT DATEADD(week, 1, [Date]), 
       iif(DATEPART(month,DATEADD(week, 1, [Date])) < validMonth + @PeriodicityRepeat, validMonth, validMonth + @PeriodicityRepeat) 
     FROM  AllDays 
     WHERE  
      DATEPART(month,[Date]) <= DATEPART(month,@EndDate) 
     and DATEPART(year,[Date]) <= DATEPART(year,@EndDate) 
      ), 
rankedDays 
    AS(  
    SELECT [Date], validMonth, 
      row_number() over (partition by DATEPART(month, [Date]) order by [Date]) ascOrder, 
      row_number() over (partition by DATEPART(month, [Date]) order by [Date] desc) descOrder 
    FROM AllDays 
    WHERE DATEPART(month, [Date]) = validMonth 
) 
select [Date] 
from rankedDays 
where ((ascOrder = @NumSemana and @NumSemana <=4) 
     or (descOrder = 1 and @NumSemana = 5) 
     or [Date] = @StartDate) 
    and [Date] < @EndDate 
OPTION (MAXRECURSION 0) 
1

Abfrage:

DECLARE @StartDate DATE = '2016-04-28', 
     @EndDate DATE = '2016-09-01' 

;WITH dates AS (
SELECT DATEADD(week, -5, @StartDate) as date_ 
UNION ALL 
SELECT DATEADD(week,1,date_) 
FROM dates 
WHERE DATEADD(week,1,date_) < @enddate 
), final AS (
SELECT ROW_NUMBER() OVER (PARTITION BY DATEPART(year,date_), DATEPART(month,date_) ORDER BY date_ ASC) as RN, 
     date_ 
FROM dates 
), weeks AS (
SELECT * 
FROM (VALUES 
(1,1), 
(2,2), 
(3,3), 
(4,4), 
(4,5), 
(5,4), 
(5,5) 
) as t(w1,w2) 
WHERE w1 = (SELECT RN FROM final WHERE date_ = @StartDate) 
) 


SELECT MAX(date_) as date_ 
FROM final f 
INNER JOIN weeks w ON f.RN = w.w2 
WHERE date_ between @StartDate and @EndDate AND date_ != @StartDate 
GROUP BY DATEPART(YEAR,date_), DATEPART(MONTH,date_) 
ORDER BY MAX(date_) ASC 

Ausgänge:

012.351.

Für @StartDate = 2016/04/01 und @EndDate = 2016/09/01

date_ 
---------- 
2016-05-06 
2016-06-03 
2016-07-01 
2016-08-05 

(4 row(s) affected) 

Für @StartDate = 2016/04/12 und @EndDate = 2016/09/01

date_ 
---------- 
2016-05-10 
2016-06-14 
2016-07-12 
2016-08-09 

(4 row(s) affected) 

Für @StartDate = 2016/04/28 und @EndDate = 2016/09/01

date_ 
---------- 
2016-05-26 
2016-06-30 
2016-07-28 
2016-08-25 

(4 row(s) affected) 
+0

funktioniert auch !!! +1 – CesarMiguel

Verwandte Themen