我也会把我的帽子扔进擂台。 :-)
DECLARE @Date datetime = '01/11/2015'
DECLARE @StartDate datetime = DATEADD(d, (1 - (DATEDIFF(d, CAST('1899.12.31' AS datetime), @Date - 6) % 7)), @Date - 6) -- MONDAY
DECLARE @EndDate datetime = DATEADD(d, (5 - (DATEDIFF(d, CAST('1899.12.31' AS datetime), @Date - 6) % 7)), @Date - 6) -- FRIDAY
SELECT '@Date' as Variable ,CONVERT(date, @Date) as DateValue ,DATENAME(dw, @Date) as DayOfTheWeek
UNION SELECT '@StartDate' as Variable ,CONVERT(date, @StartDate) as DateValue ,DATENAME(dw, @StartDate) as DayOfTheWeek
UNION SELECT '@EndDate' as Variable ,CONVERT(date, @EndDate) as DateValue ,DATENAME(dw, @EndDate) as DayOfTheWeek
-- Variable DateValue DayOfTheWeek
-- ---------- ---------- ------------
-- @Date 2015-01-11 Sunday
-- @StartDate 2015-01-05 Monday
-- @EndDate 2015-01-09 Friday
奖励:在这里,您可以使用相同的技术生成 5 个工作日的快速表格。
SELECT DATENAME(dw, DATEADD(d, TT.DaysToAdd, DATEADD(d, (1 - (DATEDIFF(d, CAST('1899.12.31' AS datetime), @Date - 6) % 7)), @Date - 6))) as DayOfTheWeek
, DATEADD(d, TT.DaysToAdd, DATEADD(d, (1 - (DATEDIFF(d, CAST('1899.12.31' AS datetime), @Date - 6) % 7)), @Date - 6)) as DateValue
FROM (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1 as DaysToAdd FROM (VALUES(0),(0),(0),(0),(0)) a(n)) as TT
-- DayOfTheWeek DateValue
-- ------------------------------ -----------------------
-- Monday 2015-01-05 00:00:00.000
-- Tuesday 2015-01-06 00:00:00.000
-- Wednesday 2015-01-07 00:00:00.000
-- Thursday 2015-01-08 00:00:00.000
-- Friday 2015-01-09 00:00:00.000
这里有一个解释:
1) 首先我们需要知道从什么日期开始我们的评估。对于此示例,我们选择使用 2015 年 1 月 11 日星期日。
DECLARE @Date2 datetime = '01/11/2015'
1b) 给定日期值,这是一种很好的获得星期几名称的奖励技巧
SELECT @Date2 as DateValue, DATENAME(dw, @Date2) as DayOfTheWeek
2) 接下来,我们需要确定性地(基于美国日历)知道给定的星期几在数字上介于 1 和 7 之间
- 注意:1899.12.31 是 1900.01.01 之前的第一个星期日,这是 SmallDateTime 数据类型的最小值。
- 注意:是的,您可以像这样更简单地使用 DATEPART(dw, @Date),但鉴于某些服务器环境可能有不同的配置,它不是确定性的
-
结果:1 = 星期日 | 2 = 星期一 | 3 = 星期二 | 4 = 星期三 | 5 = 星期四 | 6 = 星期五 | 7 = 星期六
SELECT ((DATEDIFF(d, CAST('1899.12.31' AS datetime), @Date2) % 7) + 1) [DayOfWeek Deterministic (Based on US)]
3) 现在,给定任何日期,您应该有一种确定性的方式来确定该周的星期一
SELECT DATEADD(d, (1 - (DATEDIFF(d, CAST('1899.12.31' AS datetime), @Date2) % 7)), @Date2) as [Monday Day of the Week - Deterministic (Based on US)]
4) 现在,给定任何日期,您应该有一种确定性的方法来确定给定周的星期五
SELECT DATEADD(d, (5 - (DATEDIFF(d, CAST('1899.12.31' AS datetime), @Date2) % 7)), @Date2) as [Monday Day of the Week - Deterministic (Based on US)]
5) 我们需要的最后一个日期操作技术是知道如何进入一个工作日的第一个完整周发生在它之前的一周。例如,如果我们在星期天并从中减去 1 天,那么我们就到了星期六,这使我们处于前一周,即工作日的第一个完整周。或者,如果我们也从星期一减去 1 天,它只会让我们到星期日,而不是前一周,所以减去 1 天是不够的。另一方面,如果我们是在星期六并减去 7 天,我们会超过工作日的前一周,进入前一周,这太远了。这是一个分析的总结,以找出可以减去的神奇数字是什么,这将适用于一周中的任何一天。如下所示,幻数是 6。
-- DAYS TO SUBTRACT
-- Day of the Week - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7
-- =============== ==== ==== ==== ==== ==== ==== ==== ====
-- Sunday Bad Good Good Good Good Good Good Good
-- Monday Bad Bad Good Good Good Good Good Good
-- Tuesday Bad Bad Bad Good Good Good Good Good
-- Wednesday Bad Bad Bad Bad Good Good Good Good
-- Thursday Bad Bad Bad Bad Bad Good Good Good
-- Friday Bad Bad Bad Bad Bad Bad Good Good
-- Saturday Good Good Good Good Good Good Good Bad
BONUS)如果您想将所有工作日都放在小表中,那么您还需要使用基于零的快速“计数表”。有很多方法可以做到这一点,所以选择你的口味。这里有几个。
SELECT * FROM (SELECT 0 as DaysToAdd UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4) as TT
SELECT * FROM (SELECT TOP 5 ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1 as DaysToAdd FROM sys.all_columns a CROSS JOIN sys.all_columns b) as TT
SELECT * FROM (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1 as DaysToAdd FROM (VALUES(0),(0),(0),(0),(0)) a(n)) as TT