SQL Server:使用带 ISOWK 参数的 DATEPART 将一周的第一天更改为星期日

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)

Tab*_*man 5

这是设计使然。根据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 日的那一周。