【问题标题】:Epi-week query/method for SQL ServerSQL Server 的 Epi-week 查询/方法
【发布时间】:2017-09-07 02:01:25
【问题描述】:

epi-week 的定义如下:

“根据定义,一年中的第一个 Epi 周在 1 月的第一个星期六结束,只要它在该月至少四天。每个 Epi 周从星期日开始,到星期六结束。”

参考:1

我用服务器语言 (C#/Java) 实现了它们,但我的问题是从 SQL Server 存储过程返回一个 Epi 周和 Epi 年

【问题讨论】:

    标签: sql sql-server datepart


    【解决方案1】:

    如果您还没有 Calendar 表,我强烈建议您在数据库中创建它。

    这是一个表格,在足够长的时间内每天都有一行,足以满足您的需求。

    在此类表中添加一列 EpiWeek 并填充一次。然后在您需要的任何地方使用,而不是即时计算。

    日历表在许多领域都很有用,并有助于使用基于 SQL 集的查询来解决各种问题。日历表是Numbers 表的特例,也经常有用。

    详细示例见:

    Why should I consider using an auxiliary calendar table?

    这篇文章有一个关于 ISO 周数的部分。我不确定 ISO 周和 Epi 周是否相同,但您可以查看 Aaron Bertrand 如何计算 ISO 周数的示例:

    很多很多人对 SQL Server 计算周数的方式不满意。它在DATEPART(WEEK, <date>) 中使用的奇怪算法并不总是产生与 ISO 标准相同的数字,ISO 标准规定第 1 周是第一周有 4 天。为了解决这个问题,我们可以借用 Books Online 并创建以下函数:

    CREATE FUNCTION dbo.ISOWeek 
    ( 
        @dt SMALLDATETIME 
    ) 
    RETURNS TINYINT 
    AS 
    BEGIN 
        DECLARE @ISOweek TINYINT 
    
        SET @ISOweek = DATEPART(WEEK,@dt)+1 
            -DATEPART(WEEK,RTRIM(YEAR(@dt))+'0104') 
    
        IF @ISOweek = 0 
        BEGIN 
            SET @ISOweek = dbo.ISOweek 
            ( 
                RTRIM(YEAR(@dt)-1)+'12'+RTRIM(24+DAY(@dt)) 
            ) + 1 
        END 
    
        IF MONTH(@dt) = 12 AND DAY(@dt)-DATEPART(DW,@dt) >= 28 
        BEGIN 
            SET @ISOweek=1 
        END 
    
        RETURN(@ISOweek) 
    END 
    GO
    

    然后我们可以更新表格:

    UPDATE Calendar SET W = dbo.ISOWeek(dt)
    

    另外,这里有几个关于数字表的链接:

    You REQUIRE a Numbers table!

    Generate a set or sequence without loops

    【讨论】:

    • 我们可以优化isoweek=0条件部分为: --只需设置去年最后一个日期的epiweek IF ISOweek = 0 BEGIN SET ISOweek = dbo.ISOweek ( RTRIM(YEAR(dt)- 1)+'1231') END
    • 另外,我们需要通过一些额外的逻辑来更新 Epiyear(可能你仍然认为这不是这个 SO 问题的一部分),因为如果一周改变但年份仍然显示同一年(所以改变的epiweek应该是另一年)
    • @Aarush,我的意思是向您展示该方法,以便您可以根据需要进行调整。很高兴您发现我的回答很有用。
    【解决方案2】:

    查找 EpiWeek:

     CREATE FUNCTION [dbo].[EPIWeek] 
    ( 
        @Date SMALLDATETIME 
    ) 
    RETURNS TINYINT 
    AS 
    BEGIN 
        DECLARE @EPIWeek TINYINT 
    
        --Fix first epi week (i.e if 0401 of year falls in first week, then it will give perfect start epiweek)
        SET @EPIWeek = DATEPART(WEEK,@Date)+1 - DATEPART(WEEK,RTRIM(YEAR(@Date))+'0104') 
        --if 0401 of year falls in second week, then change to epiweek of last year
        IF @EPIWeek = 0 
        BEGIN 
            SET @EPIWeek = dbo.EPIWeek(RTRIM(YEAR(@Date)-1)+'1231')
        END 
    
        --Fix last epi week (ie. If any date after 2812 falls below wednesday, then it is first epiweek of next year)
        IF MONTH(@Date) = 12 AND DAY(@Date)-DATEPART(DW,@Date) >= 28 
        BEGIN 
            SET @EPIWeek=1 
        END 
    
        RETURN(@EPIWeek) 
    END 
    

    查找 EpiYear:

    CREATE FUNCTION [dbo].[EPIYear] 
    ( 
        @Date DATETIME
    ) 
    RETURNS INT
    AS
    BEGIN
      DECLARE @EPIYear INT = DATEPART(YEAR, @Date);
    
      -- WHEN January 1-3 may belong to the previous year
      IF (DATEPART(MONTH, @DATE) = 1 AND dbo.EPIWeek(@DATE) > 50)
        SET @EPIYear = @EPIYear - 1;
    
      -- WHEN December 29-31 may belong to the next year
      IF (DATEPART(MONTH, @DATE) = 12 AND dbo.EPIWeek(@DATE) < 45)
        SET @EPIYear = @EPIYear + 1;
    
      RETURN @EPIYear;
    
    END
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-10-29
      • 2011-03-10
      • 2014-12-25
      • 2013-05-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多