【问题标题】:Generate list of dates based on the day and occurrence of the month根据日期和月份的出现生成日期列表
【发布时间】:2016-04-01 11:33:23
【问题描述】:

我想根据日期的星期几和月份中出现的次数生成两个日期之间每个月的日期列表。假设我有@StartDate = 2016/04/01@EndDate = 2016/09/01,我检查@StartDate 是在四月的第一个星期五,然后@EndDate 将为每个月的第一个星期五创建日期:

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

如果@StartDate = 2016/04/12@EndDate = 2016/09/01,我注意到@StartDate 是四月的第二个星期二,然后每个月的第二个星期二去:

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

如果@StartDate = 2016/04/28@EndDate = 2016/09/01,我注意到@StartDate 是在四月的最后一个星期四:

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

在最后一种情况下,我需要验证每个月的周数,因为仅存在 4 周或 5 周的月份,我想要最后一次出现。

我做了什么?我找到了一个代码,每个月第三周的每个星期一都给我,我采用了一点来获得@StartDate@EndDate

;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

【问题讨论】:

  • 您的规则不明确。如何区分一个月的第四个星期一和最后一个星期一?
  • @GordonLinoff 你说的是代码吗?我需要调整它来做到这一点
  • 您是否考虑过使用calendar table?从包含工作日和周数的所有日期的完整列表中,您将始终能够筛选出您需要的日期。
  • @destination-data 日历表是临时表吗?它对我有什么帮助?
  • 您的表格可以包含一个字段,用于标识每个月的最后一周。这就是这些表真正发挥作用的地方。它们允许您标记和识别对您而言重要的内容。

标签: sql sql-server database


【解决方案1】:

所以,它是:

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)

【讨论】:

    【解决方案2】:

    查询

    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
    

    输出

    对于@StartDate = 2016/04/01@EndDate = 2016/09/01

    date_
    ----------
    2016-05-06
    2016-06-03
    2016-07-01
    2016-08-05
    
    (4 row(s) affected)
    

    对于@StartDate = 2016/04/12@EndDate = 2016/09/01

    date_
    ----------
    2016-05-10
    2016-06-14
    2016-07-12
    2016-08-09
    
    (4 row(s) affected)
    

    对于@StartDate = 2016/04/28@EndDate = 2016/09/01

    date_
    ----------
    2016-05-26
    2016-06-30
    2016-07-28
    2016-08-25
    
    (4 row(s) affected)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-10-08
      • 1970-01-01
      • 1970-01-01
      • 2019-07-07
      • 1970-01-01
      • 2021-08-18
      • 2017-03-23
      • 1970-01-01
      相关资源
      最近更新 更多