(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
答案 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