SQL Server日期表:以编程方式查找给定月份中的最后一个星期日

时间:2016-12-03 23:29:07

标签: sql sql-server

(SQL Server 2008及更高版本):我需要更新dimDate表以包含以下列:

  • 本月最后一个星期天:
  • 本月最后一个星期一:
  • 本月最后一个星期二:
  • 本月最后一个星期三:
  • 本月最后一个星期四:
  • 本月最后一个星期五:
  • 本月最后一个星期六:

别误会我的意思;通过以下代码在SQL中找到月份的最后一天非常简单:

CONVERT(DATE, DATEADD(DD, - (DATEPART(DD, (DATEADD(MM, 1, DayInTime)))), DATEADD(MM, 1, DayInTime))) AS [LastDayOfTheMonth]

但我在互联网上找不到任何地方,我承认不会花费超过2个小时的搜索时间,人们公开展示了如何识别最后一个(插入日期名称)

因此,我解决了这个等式,并将其发布在这里,以防它对其他人有用,或者,如果有人有一个更简单的方法我可以使用,但根本看不到它。

通过预先填充的dimDates表填充dimNumbers表:

 IF OBJECT_ID('dbo.dimNumbers') IS NOT NULL 
      DROP TABLE dbo.dimNumbers;

DECLARE @UpperBound INT = 1000000;

;WITH cteN(Number) AS
(
     SELECT 
         ROW_NUMBER() OVER (ORDER BY s1.[object_id]) - 1
     FROM 
         sys.all_columns AS s1
     CROSS JOIN 
         sys.all_columns AS s2
)
SELECT [Number] 
INTO ref.dimNumbers
FROM cteN 
WHERE [Number] <= @UpperBound;

CREATE UNIQUE CLUSTERED INDEX CIX_dimNumbers ON ref.dimNumbers([Number]);

然后通过以下方式填充昏暗的日期表。是的,我很懒,希望SQL执行所有可能的计算。

DECLARE @YearsToPopulate INT = 130;

-- Use the Magic of SQL to identify 1 Jan and then 31st December at the various edges of the required date time frames.
DECLARE @StartDate DATE = DATEADD(yy, DATEDIFF(yy,0,DATEADD(yyyy,-@YearsToPopulate,GETDATE())), 0);
DECLARE @EndDate DATE = DATEADD(yy, DATEDIFF(yy,0,DATEADD(yyyy,@YearsToPopulate,GETDATE())) + 1, -1);

DECLARE @RecordsToCreate INT =  DATEDIFF(dd,@StartDate,@EndDate);

;WITH MyFullDateRange AS 
(
   SELECT TOP (@RecordsToCreate)  
       CAST(DATEADD(dd, Number, @StartDate) AS DATE) AS DayInTime
   FROM 
       ref.[dimNumbers]
) 
SELECT 
    --Insert Formulas here, using [DayInTime] as the Variable
    -- The Formulas I have used here are not the topic of this discussion.
FROM 
    MyFullDateRange

所以,我花了几个小时来证明,但我终于提出了一个简单,可重复的模式来发现“月末的最后一个(插入日期名称)”。

注意:将以下内容放在上面的SELECT声明中。

--Sunday [DayOfWeek] = 1.. Need to convert 1 to 0 <-> N + (7 - 1) % 7
DATEADD(DD,
        - ((DATEPART(dw,  DATEADD(DD, - (DATEPART(DD, (DATEADD(MM, 1, DayInTime)))), DATEADD(MM, 1, DayInTime)))) + (7 - 1) ) % 7 ,
        CONVERT(DATE, DATEADD(DD, - (DATEPART(DD, (DATEADD(MM, 1, DayInTime)))), DATEADD(MM, 1, DayInTime)))
    )
    AS [LastsSundayOfTheMonth]


--Monday [DayOfWeek] = 2.. Need to convert 2 to 0 <->  N + (7 - 2) % 7   
DATEADD(DD,
            - ((DATEPART(dw,  DATEADD(DD, - (DATEPART(DD, (DATEADD(MM, 1, DayInTime)))), DATEADD(MM, 1, DayInTime)))) + (7 - 2) ) % 7    ,
            CONVERT(DATE, DATEADD(DD, - (DATEPART(DD, (DATEADD(MM, 1, DayInTime)))), DATEADD(MM, 1, DayInTime)))
        )
        AS  [LastMondayOfTheMonth]


--Tuesday [DayOfWeek] = 3.. Need to convert 3 to 0 <->  N + (7 - 3) % 7
DATEADD(DD,
            - ((DATEPART(dw,  DATEADD(DD, - (DATEPART(DD, (DATEADD(MM, 1, DayInTime)))), DATEADD(MM, 1, DayInTime))))  + (7 -3) ) % 7   ,
            CONVERT(DATE, DATEADD(DD, - (DATEPART(DD, (DATEADD(MM, 1, DayInTime)))), DATEADD(MM, 1, DayInTime)))
        )
        AS [LastTuesdayOfTheMonth]

--Wednesday [DayOfWeek] = 4.. Need to convert 4 to 0 <-> N + (7 - 4) % 7
DATEADD(DD,
            - ((DATEPART(dw,  DATEADD(DD, - (DATEPART(DD, (DATEADD(MM, 1, DayInTime)))), DATEADD(MM, 1, DayInTime)))) + (7 - 4) ) % 7   ,
            CONVERT(DATE, DATEADD(DD, - (DATEPART(DD, (DATEADD(MM, 1, DayInTime)))), DATEADD(MM, 1, DayInTime)))
        )
        AS [LastWednesdayOfTheMonth]

--Thursday [DayOfWeek] = 5.. Need to convert 5 to 0 <-> N + (7 - 5 ) % 7
DATEADD(DD,
            - ((DATEPART(dw,  DATEADD(DD, - (DATEPART(DD, (DATEADD(MM, 1, DayInTime)))), DATEADD(MM, 1, DayInTime))))  + (7 - 5) ) % 7   ,
            CONVERT(DATE, DATEADD(DD, - (DATEPART(DD, (DATEADD(MM, 1, DayInTime)))), DATEADD(MM, 1, DayInTime)))
        )
        AS [LastThursdayOfTheMonth]

--Friday [DayOfWeek] = 6.. Need to convert 6 to 0 <-> N + (7 - 6 ) % 7
DATEADD(DD,
            - ((DATEPART(dw,  DATEADD(DD, - (DATEPART(DD, (DATEADD(MM, 1, DayInTime)))), DATEADD(MM, 1, DayInTime))))  + (7-6) ) % 7   ,
            CONVERT(DATE, DATEADD(DD, - (DATEPART(DD, (DATEADD(MM, 1, DayInTime)))), DATEADD(MM, 1, DayInTime)))
        )
        AS [LastFridayOfTheMonth]


--Saturday [DayOfWeek] = 7.. Need to convert 7 to 0 <-> N + (7 - 7 ) % 7
DATEADD(DD,
            - ((DATEPART(dw,  DATEADD(DD, - (DATEPART(DD, (DATEADD(MM, 1, DayInTime)))), DATEADD(MM, 1, DayInTime))))  + (7-7) ) % 7   ,
            CONVERT(DATE, DATEADD(DD, - (DATEPART(DD, (DATEADD(MM, 1, DayInTime)))), DATEADD(MM, 1, DayInTime)))
        )
        AS [LastsSaturdayOfTheMonth]

我希望这对其他人有用,或者有人能够指出一种更简单的方法来执行这些操作。

扩展[Matts] SQL Server 2012答案:

以下代码适用于SQL Server 2012及更高版本,并且希望能够清楚地确定每天的识别方式。 (如果不是,请告诉我,我会澄清)

DECLARE @YearsToPopulate INT = 130;

-- Use the Magic of SQL to identify 1 Jan and then 31st December at the various edges of the required date time frames.
DECLARE @Date1 DATE = DATEADD(yy, DATEDIFF(yy,0,DATEADD(yyyy,-@YearsToPopulate,GETDATE())), 0);
DECLARE @Date2 DATE = DATEADD(yy, DATEDIFF(yy,0,DATEADD(yyyy,@YearsToPopulate,GETDATE())) + 1, -1);

DECLARE @RecordsToCreate INT =  DATEDIFF(dd,@Date1,@Date2);

WITH MyFullDateRange AS 
(
   SELECT TOP (@RecordsToCreate)  CAST(DATEADD(dd, Number, @Date1) AS DATE) AS DayInTime
   FROM ref.[dimNumbers]
) 

SELECT  DayInTime
    --Sunday [DayOfWeek] = 1.. Need to convert 1 to 0 <-> N + (0 - 1) % 7
    ,LastSundayOfMonth = DATEADD(DAY, 0 - (@@DATEFIRST - 1 + DATEPART(dw,EOMONTH(DayInTime))) % 7, EOMONTH(DayInTime))

    --Monday [DayOfWeek] = 2.. Need to convert 2 to 0 <->  N + (0 - 2) % 7   
    ,LastMondayOfMonth = DATEADD(DAY, 0 - (@@DATEFIRST - 2 + DATEPART(dw,EOMONTH(DayInTime))) % 7, EOMONTH(DayInTime))

    --Tuesday [DayOfWeek] = 3.. Need to convert 2 to 0 <->  N + (0 - 3) % 7   
    ,LastTuesdayOfMonth = DATEADD(DAY, 0 - (@@DATEFIRST - 3 + DATEPART(dw,EOMONTH(DayInTime))) % 7, EOMONTH(DayInTime))

    --Wednesday [DayOfWeek] = 4.. Need to convert 4 to 0 <->  N + (0 - 4) % 7   
    ,LastWednesdayOfMonth = DATEADD(DAY, 0 - (@@DATEFIRST - 4 + DATEPART(dw,EOMONTH(DayInTime))) % 7, EOMONTH(DayInTime))

    --Thursday [DayOfWeek] = 5.. Need to convert 2 to 0 <->  N + (0 - 5) % 7   
    ,LastThursdayOfMonth = DATEADD(DAY, 0 - (@@DATEFIRST - 5 + DATEPART(dw,EOMONTH(DayInTime))) % 7, EOMONTH(DayInTime))

    --Friday [DayOfWeek] = 6.. Need to convert 2 to 0 <->  N + (0 - 6) % 7   
    ,LastFridayOfMonth = DATEADD(DAY, 0 - (@@DATEFIRST - 6 + DATEPART(dw,EOMONTH(DayInTime))) % 7, EOMONTH(DayInTime))

    --Saturday [DayOfWeek] = 7.. Need to convert 2 to 0 <->  N + (0 - 7) % 7   
    ,LastSaturdayOfMonth = DATEADD(DAY, 0 - (@@DATEFIRST - 7 + DATEPART(dw,EOMONTH(DayInTime))) % 7, EOMONTH(DayInTime))

FROM MyFullDateRange;

如果我不必支持SQL Server 2008,我会使用此代码。

更多SQL Server 2012以后的代码:

不幸的是,我希望这是一个很好的选择,但是没有用。请记住,解决方案需要适合dimDate表。有什么建议可以改善吗?我不喜欢这个解决方案的部分是,我需要执行dimDate表的双重更新。

DECLARE @YearsToPopulate INT = 130;

DECLARE @Date1 DATE = DATEADD(yy, DATEDIFF(yy,0,DATEADD(yyyy,-@YearsToPopulate,GETDATE())), 0);
DECLARE @Date2 DATE = DATEADD(yy, DATEDIFF(yy,0,DATEADD(yyyy,@YearsToPopulate,GETDATE())) + 1, -1);

DECLARE @RecordsToCreate INT =  DATEDIFF(dd,@Date1,@Date2);

WITH MyFullDateRange AS 
(
   SELECT TOP (@RecordsToCreate)  CAST(DATEADD(dd, Number, @Date1) AS DATE) AS DayInTime
   FROM ref.[dimNumbers]
) 
, CreateListOfDatesAndDOWs As 
(
    Select DayInTime AS DayInTime,  DatePART( DW , DayInTime ) AS DayNumber
    From MyFullDateRange
)

 Select DayInTime AS [currentDate]--SQL 2012 --   DateFromParts(Year(DayInTime),Month(DayInTime) , 1) AS [currentDate]
       ,LastSun = MAX(CASE WHEN  DayNumber=1 THEN DayInTime END)
       ,LastMon = MAX(CASE WHEN  DayNumber=2 THEN DayInTime END)
       ,LastTue = MAX(CASE WHEN  DayNumber=3 THEN DayInTime END)
       ,LastWed = MAX(CASE WHEN  DayNumber=4 THEN DayInTime END)
       ,LastThu = MAX(CASE WHEN  DayNumber=5 THEN DayInTime END)
       ,LastFri = MAX(CASE WHEN  DayNumber=6 THEN DayInTime END)
       ,LastSat = MAX(CASE WHEN  DayNumber=7 THEN DayInTime END)
 From  CreateListOfDatesAndDOWs

 Group By DayInTime --DateFromParts(Year(DayInTime),Month(DayInTime),1)--SQL 2012

因为这会返回以下结果集,对于dimDate表,它不是我们所追求的。 (我需要弄清楚如何格式化表格!)

currentDate LastSun    LastMon    LastTue    LastWed    LastThu    LastFri    LastSat
----------- ---------- ---------- ---------- ---------- ---------- ---------- ----------
1886-01-01  NULL       NULL       NULL       NULL       NULL       1886-01-01 NULL
1886-01-02  NULL       NULL       NULL       NULL       NULL       NULL       1886-01-02
1886-01-03  1886-01-03 NULL       NULL       NULL       NULL       NULL       NULL
1886-01-04  NULL       1886-01-04 NULL       NULL       NULL       NULL       NULL
1886-01-05  NULL       NULL       1886-01-05 NULL       NULL       NULL       NULL
1886-01-06  NULL       NULL       NULL       1886-01-06 NULL       NULL       NULL
1886-01-07  NULL       NULL       NULL       NULL       1886-01-07 NULL       NULL
1886-01-08  NULL       NULL       NULL       NULL       NULL       1886-01-08 NULL
1886-01-09  NULL       NULL       NULL       NULL       NULL       NULL       1886-01-09
1886-01-10  1886-01-10 NULL       NULL       NULL       NULL       NULL       NULL
1886-01-11  NULL       1886-01-11 NULL       NULL       NULL       NULL       NULL
1886-01-12  NULL       NULL       1886-01-12 NULL       NULL       NULL       NULL
1886-01-13  NULL       NULL       NULL       1886-01-13 NULL       NULL       NULL
1886-01-14  NULL       NULL       NULL       NULL       1886-01-14 NULL       NULL
1886-01-15  NULL       NULL       NULL       NULL       NULL       1886-01-15 NULL
1886-01-16  NULL       NULL       NULL       NULL       NULL       NULL       1886-01-16
1886-01-17  1886-01-17 NULL       NULL       NULL       NULL       NULL       NULL
1886-01-18  NULL       1886-01-18 NULL       NULL       NULL       NULL       NULL
1886-01-19  NULL       NULL       1886-01-19 NULL       NULL       NULL       NULL
1886-01-20  NULL       NULL       NULL       1886-01-20 NULL       NULL       NULL
1886-01-21  NULL       NULL       NULL       NULL       1886-01-21 NULL       NULL
1886-01-22  NULL       NULL       NULL       NULL       NULL       1886-01-22 NULL
1886-01-23  NULL       NULL       NULL       NULL       NULL       NULL       1886-01-23
1886-01-24  1886-01-24 NULL       NULL       NULL       NULL       NULL       NULL
1886-01-25  NULL       1886-01-25 NULL       NULL       NULL       NULL       NULL
1886-01-26  NULL       NULL       1886-01-26 NULL       NULL       NULL       NULL
1886-01-27  NULL       NULL       NULL       1886-01-27 NULL       NULL       NULL
1886-01-28  NULL       NULL       NULL       NULL       1886-01-28 NULL       NULL
1886-01-29  NULL       NULL       NULL       NULL       NULL       1886-01-29 NULL
1886-01-30  NULL       NULL       NULL       NULL       NULL       NULL       1886-01-30
1886-01-31  1886-01-31 NULL       NULL       NULL       NULL       NULL       NULL
1886-02-01  NULL       1886-02-01 NULL       NULL       NULL       NULL       NULL
1886-02-02  NULL       NULL       1886-02-02 NULL       NULL       NULL       NULL
1886-02-03  NULL       NULL       NULL       1886-02-03 NULL       NULL       NULL
1886-02-04  NULL       NULL       NULL       NULL       1886-02-04 NULL       NULL
1886-02-05  NULL       NULL       NULL       NULL       NULL       1886-02-05 NULL
1886-02-06  NULL       NULL       NULL       NULL       NULL       NULL       1886-02-06

1 个答案:

答案 0 :(得分:0)

SQL server 2012+(因为使用了EOMONTH()

DATEADD(DAY, 0 - (@@DATEFIRST - 1 + DATEPART(dw,EOMONTH(DateCol))) % 7, EOMONTH(DateCol))

无论DATEFIRST值设置为什么,此公式都将有效。

工作示例(显示其有效的链接http://rextester.com/ZHJL66222):

DECLARE @Table AS TABLE (DateCol DATE)
INSERT INTO @Table VALUES ('1/15/2016'),('2/15/2016'),('3/15/2016'),
    ('4/15/2016'),('5/15/2016'),('6/15/2016'),('7/15/2016'),('8/15/2016'),
    ('9/15/2016'),('10/15/2016'),('11/15/2016'),('12/15/2016')


;WITH cte AS (
    SELECT
       *
       ,LastSundayOfMonth = DATEADD(DAY, 0 - (@@DATEFIRST - 1 + DATEPART(dw,EOMONTH(DateCol))) % 7, EOMONTH(DateCol))
    FROM
       @Table
)

SELECT
    *
    ,CheckToEnsure = DATENAME(dw,LastSundayOfMonth)
FROM
    cte

对于SQL 2008,可以将EOMONTH()切换为以下内容:

DATEADD(DAY, - DATEPART(DAY,DateCol),DATEADD(MONTH,1,DateCol))

对于一周中的其他日子,可以调整以查看其他答案:https://stackoverflow.com/a/40942693/5510627

相关问题