【问题标题】:Getting week number off a date in MS SQL Server 2005?在 MS SQL Server 2005 中获取日期的周数?
【发布时间】:2008-12-08 07:55:34
【问题描述】:

是否可以创建一个选择周数(不是星期几 - 或一周中的天数)的 sql 语句。我正在创建一个视图来选择这个额外的信息以及其他几个字段,因此不能使用存储过程。我知道可以创建一个 UDF 来解决问题,但如果可能的话,我宁愿只向该数据库添加一个视图,而不是视图和函数。

有什么想法吗?我也是从哪里来的,一周从星期一开始,第一周是一年中的第一周,至少有 4 天。

相关:

How do I calculate the week number given a date?

【问题讨论】:

    标签: sql-server tsql


    【解决方案1】:

    请注意,正确的周数会有所不同,具体取决于文化。周数取决于几个不同国家/地区的假设,请参阅Wikipedia article on the matter。有一个适用于周数的ISO standard (ISO 8601)。

    SQL 服务器集成DATEPART() 功能不一定做正确的事。 SQL Server 假设第 1 周的第 1 天是 1 月 1 日,对于许多应用程序来说这是错误的。

    正确计算周数并非易事,在网上可以找到不同的实现。例如,有一个 UDF 可以计算 ISO week numbers from 1930-2030,这是众多其他函数之一。你必须检查什么对你有用。

    这个来自Books Online(虽然你可能想用the one from Jonas Lincoln's answer,BOL版本好像不对):

    CREATE FUNCTION ISOweek  (@DATE DATETIME)
    RETURNS INT
    AS
    BEGIN
       DECLARE @ISOweek INT
       SET @ISOweek = DATEPART(wk,@DATE) 
                      +1 
                      -DATEPART(wk,CAST(DATEPART(yy,@DATE) AS CHAR(4))+'0104')
       -- Special cases: Jan 1-3 may belong to the previous year
       IF (@ISOweek=0)
          SET @ISOweek = dbo.ISOweek(CAST(DATEPART(yy,@DATE) - 1
                         AS CHAR(4))+'12'+ CAST(24+DATEPART(DAY,@DATE) AS CHAR(2)))+1
       -- Special case: Dec 29-31 may belong to the next year
       IF ((DATEPART(mm,@DATE)=12) AND
          ((DATEPART(dd,@DATE)-DATEPART(dw,@DATE))>= 28))
          SET @ISOweek=1
       RETURN(@ISOweek)
    END
    GO
    

    【讨论】:

    • 谢谢 - 除了 UDF 之外,我喜欢关于周数的明确信息 - 我想我会通过创建一个包含我可以做的周数(或第 1 周的第一天)的表来解决它在我看来,简单的逻辑。不好的部分是获得额外的表格 - 但我认为它击败了难以阅读的 UDF ;)
    • 但是,如果您要检查 UDF 是否这样做 - 它会比额外的表更快(如果这对您很重要),而且您也不必经常阅读它。 ;-) 正如我所说,如果您不喜欢/不能使用这个,还有其他实现。
    • 我认为调用这个 udf 会比加入索引日期/周表需要更长的时间?我可能是错的,但专注于这项任务是保持低复杂性(每个人都知道如何进行内部连接,但不是每个人都会理解这个 udf)。感谢您提出它 - 我可能需要对其进行测试;)
    • 听说过 DATEPART(ISO_WEEK,@DATE) 吗?
    • @Quandary 是的,我有,但是 sql-server 2005 没有
    【解决方案2】:

    您需要 ISO 周。来自http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=60510,这是一个实现:

    drop function dbo.F_ISO_WEEK_OF_YEAR
    go
    create function dbo.F_ISO_WEEK_OF_YEAR
        (
        @Date   datetime
        )
    returns     int
    as
    /*
    Function F_ISO_WEEK_OF_YEAR returns the
    ISO 8601 week of the year for the date passed.
    */
    begin
    
    declare @WeekOfYear     int
    
    select
        -- Compute week of year as (days since start of year/7)+1
        -- Division by 7 gives whole weeks since start of year.
        -- Adding 1 starts week number at 1, instead of zero.
        @WeekOfYear =
        (datediff(dd,
        -- Case finds start of year
        case
        when    NextYrStart <= @date
        then    NextYrStart
        when    CurrYrStart <= @date
        then    CurrYrStart
        else    PriorYrStart
        end,@date)/7)+1
    from
        (
        select
            -- First day of first week of prior year
            PriorYrStart =
            dateadd(dd,(datediff(dd,-53690,dateadd(yy,-1,aa.Jan4))/7)*7,-53690),
            -- First day of first week of current year
            CurrYrStart =
            dateadd(dd,(datediff(dd,-53690,aa.Jan4)/7)*7,-53690),
            -- First day of first week of next year
            NextYrStart =
            dateadd(dd,(datediff(dd,-53690,dateadd(yy,1,aa.Jan4))/7)*7,-53690)
        from
            (
            select
                --Find Jan 4 for the year of the input date
                Jan4    = 
                dateadd(dd,3,dateadd(yy,datediff(yy,0,@date),0))
            ) aa
        ) a
    
    return @WeekOfYear
    
    end
    go
    

    【讨论】:

    • 谢谢,今天刚好需要这个。它比公认的答案更正确。
    • 听说过 DATEPART(ISO_WEEK,@DATE) 吗?
    • @Quandary 他正在为不支持 ISO_WEEK 的 SQL Server 2005 寻找解决方案。
    • 对我来说,这比 Tomalak 的回答提供了更好的结果 - 对于 2014-09-28,它返回 39(这是正确的!-weeknumber.net/?q=2014-09-28),而 Tomalak 的回答返回 40。
    【解决方案3】:

    看起来DATEPART mssql function 应该可以帮助您解决...

    DATEPART(wk, ‘Jan 1, xxxx’) = 1
    

    好吧,我会的……原来有一种方法可以设置一周的第一天,DATEFIRST

    SET DATEFIRST 1 -- for monday
    

    更新:现在我更好地理解了 OP 想要什么......这是自定义逻辑。我不认为 MSSQL 会有如此丰富的自定义功能。但我可能错了......我认为你必须在这里推出自己的 UDF......对不起

    【讨论】:

    • 不,Hojou 正在寻找 ISO 周数 (ISO 8601)。这必须用 UDF 来解决。
    【解决方案4】:

    忘记其他答案

    问题指定“一周从星期一开始,第 1 周是一年中的第一周,至少有 4 天。”这是 ISO 8601 标准,这个答案是什么提供。此功能在我们网站的生产环境中使用。

    这就是你所需要的:

    CREATE FUNCTION ISOweek  (@DATE DATETIME)
    RETURNS INT
    AS
    BEGIN
        RETURN (datepart(DY, datediff(d, 0, @DATE) / 7 * 7 + 3)+6) / 7
    END
    GO
    

    【讨论】:

      【解决方案5】:

      这将返回您在引号中输入的日期的周数

      SELECT DATEPART( wk, 'enter the date over here' )
      

      【讨论】:

      • 这不能保证问题指定的 ISO 8601 标准
      【解决方案6】:

      看起来 datepart 可以帮助您完成部分任务,但您必须根据给定年份 1 月 1 日的星期几进行调整才能获得正确的周数。我对 T-SQL 不够熟悉,无法做到这一点,但应该可以。可惜没有MySQL中的模式参数

      【讨论】:

        【解决方案7】:

        您是否考虑过使用 WEEK 功能?

        这将为您提供指定日期的一年中的哪一周。

        SELECT { fn WEEK(GETDATE()) } AS WeekNumber, { fn WEEK(CONVERT(DATETIME, '2008-01-01 00:00:00', 102)) } AS FirstWeekOfYear, { fn WEEK(CONVERT(DATETIME, '2008-12-31 00:00:00', 102)) } AS LastWeekOfYear
        

        这会输出以下 SQL2000 和 SQL2005:

        • 周数:50
        • FirstWeekOfYear:1
        • LastWeekOfYear:53

        我希望这会有所帮助:)

        【讨论】:

        • 看起来它有同样的问题 DatePart(wk, getdate()) 并且不起作用。 SELECT { fn WEEK('2003-12-31') } AS WeekNumber 给我 53 这是错误的,因为正确的周数是 1
        【解决方案8】:

        为什么又一次,人们用鼹鼠山造山,这让我很吃惊?

        这么简单……

        select DATEPART(wk, GETDATE())
        

        【讨论】:

        • 这不能保证问题指定的 ISO 8601 标准
        • 但至少这是一个起点,他们可以使用自己的文化设置。
        • @Kleky,不正确。 OP 没有提及任何有关 ISO 标准的内容
        • “我也是从哪里来的,一周从星期一开始,第一周是一年中的第一周,至少有 4 天。” = ISO 标准
        猜你喜欢
        • 2011-11-09
        • 1970-01-01
        • 1970-01-01
        • 2010-11-12
        • 2013-03-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-30
        相关资源
        最近更新 更多