Eug*_*ich 3 sql t-sql sql-server sql-server-2014
我需要获取某些日期集的周数。例如,对于 2016 年 1 月,它应该类似于:
[Week Number]
53 <--- for dates from Jan 1 to Jan 2
1 <--- for dates from Jan 3 to Jan 9
2 <--- for dates from Jan 10 to Jan 16
... <--- etc.
Run Code Online (Sandbox Code Playgroud)
如您所见,一周应该从星期日开始。我使用以下函数来设置开始日期:
SET DATEFIRST 7
Run Code Online (Sandbox Code Playgroud)
这是获取周数的一个:
DATEPART(ISOWK, SOME_DATE)
Run Code Online (Sandbox Code Playgroud)
但我注意到这DATEFIRST不会影响ISOWK使用时的结果 - 周总是从星期一开始。
那么,我做错了什么?谢谢你!
更新:
我做了一个功能,看起来效果很好:
CREATE FUNCTION [dbo].[GetWeekNumber]
(
@date as DATETIME,
@offset as INT
)
RETURNS NVARCHAR(100)
BEGIN
DECLARE @weekNumber as int
DECLARE @year as int
SET @date = DATEADD(MINUTE, @offset, @date)
SET @year = DATEPART(year, DATEADD(DAY, 1 - DATEPART(WEEKDAY, @date), CAST(@date AS DATE)))
IF @@DATEFIRST = 7
BEGIN
SET @date = DATEADD(day, 1, @date)
END
SET @weekNumber = DATEPART(ISO_WEEK, @date)
RETURN concat(@year, ', Week ', right('0' + convert(nvarchar, @weekNumber), 2))
END
Run Code Online (Sandbox Code Playgroud)
您需要传递日期和时区偏移量(以分钟为单位)。并SET DATEFIRST @startDay在执行此功能之前(1 - 星期一,7 - 星期日)。例子:
DECLARE @date as DATETIME
SET @date = '2016-01-03 12:00'
SET DATEFIRST 1
SELECT dbo.GetWeekNumber(@date, 0) -- 2015, Week 53
SET DATEFIRST 7
SELECT dbo.GetWeekNumber(@date, 0) -- 2016, Week 01
Run Code Online (Sandbox Code Playgroud)
这是设计使然。根据MSDN:
ISO 8601 包括 ISO 周日期系统,即周的编号系统。每个星期都与星期四所在的年份相关联。例如,2004 年第一周 (2004W01) 从 2003 年 12 月 29 日星期一到 2004 年 1 月 4 日星期日。
所以ISOWK始终以星期四为基准,并且不受 影响DATEFIRST。
要获得您想要的结果,只需使用WEEK代替ISOWK。
更新:同样来自 MSDN:
任何年份的 1 月 1 日定义周日期部分的起始编号,例如:DATEPART (wk, 'Jan 1, xxxx') = 1,其中 xxxx 是任意年份。
让第 1 周为 1 月 3 日至 9 日的唯一方法是使用数学。从该值中减去 1 DATEPART(wk...),如果结果为 0,则将其变为 53(或者仅DATEADD在您的日期上使用以减去一周)。没有更简单的方法了,根据设计,任何一年的第一周都将是包含 1 月 1 日的那一周。