【问题标题】:SQL Server UDF for getting week of year, with first day of week argumentSQL Server UDF 用于获取一年中的一周,带有一周的第一天参数
【发布时间】:2013-08-28 19:21:52
【问题描述】:

我正在寻找与DATEPART(WEEK, @date) 等效的SQL Server UDF,但允许调用者指定一周的第一天。有点类似于 MySql 的WEEK 函数。例如:

CREATE FUNCTION Week (@date date, @firstdayofweek int)
RETURNS int
BEGIN
  -- return result would be the same as:
  --   SET DATEFIRST @firstdayofweek
  --   DATEPART(WEEK, @date)
END

我的应用程序没有机会调用SET DATEFIRST

例子:

SELECT Week('2013-08-28', 2) -- returns 35
SELECT Week('2013-08-28', 3) -- returns 36

无论 SQL Server 的 @@DATEFIRST 值如何,上述结果总是相同的。

【问题讨论】:

  • 那么如果我提交 2013-08-28 和 2,我应该返回什么?
  • 35。如果您提交 2013-08-28 和 3,您应该返回 36。
  • 2013-01-01 和 1 怎么样?另外,1 代表星期日还是星期一?
  • 1.您可以根据脚本检查结果:SET DATEFIRST 1;选择日期部分(周,'2013-01-01');
  • 1 代表星期一。周日是 7 点。DATEFIRST 文档:technet.microsoft.com/en-us/library/ms181598.aspx

标签: sql sql-server datepart


【解决方案1】:

你可以这样使用:

DATEPART(WEEK, DATEADD(DAY, 8 - @firstdayofweek, @date))

您移动的是实际日期,而不是移动一周的第一天。使用此公式,一周的第一天将使用与 MS SQL Server 使用的天数相同的数值来设置。 (周日 = 1,周六 = 7)

【讨论】:

  • 改天是行不通的,因为你可能会跨越一周的界限。例如,DATEPART(WEEK, '2013-08-31') 返回 35 (@@DATEFIRST = 7) 并且 DATEPART(WEEK, DATEADD(DAY, 8 - 1, '2013-08'31')) 返回 36。
  • 很抱歉你上面的例子不清楚。如果一周的第一天是第 7 天,则 DATEPART(WEEK, DATEADD(DAY, 8-7, '2013-08-31')) 将返回 36,因为您刚刚说一周的第一天是星期六和 8 月 31 日2013 年是 2013 年的第 36 个星期六。所以它工作正常。也许您正在尝试解决不同的问题?
  • 一些额外的清晰度,日期部分 WEEK 不受 MS SQL Server 中的 DATEFIRST 设置的影响。我找不到任何特定的文档,但我已经测试过了。无论一周的第一天是哪一天,一周都是一样的。另外,我说过 2013 年 8 月 31 日是第 36 个星期六,我应该说它标志着第 36 周的开始,实际上是第 35 个星期六。
  • 我上面的例子是正确的。 DATEPART 确实依赖于 DATEFIRST。 “当 datepart 为周 (wk, ww) 或工作日 (dw) 时,返回值取决于使用 SET DATEFIRST 设置的值。” (msdn.microsoft.com/en-us/library/ms174420.aspx)
【解决方案2】:

我找到了几篇文章帮助我回答了这个问题:

  1. Deterministic scalar function to get week of year for a date

  2. http://sqlmag.com/t-sql/datetime-calculations-part-3

也许可以简化这个 UDF,但它给了我想要的东西:

CREATE FUNCTION Week (@date DATETIME, @dateFirst INT)
RETURNS INT
BEGIN
  DECLARE @normalizedWeekOfYear INT = DATEDIFF(WEEK, DATEADD(YEAR, DATEDIFF(YEAR, 0, @date), 0), @date) + 1
  DECLARE @jan1DayOfWeek INT = DATEPART(WEEKDAY, DATEADD(YEAR, DATEDIFF(YEAR, 0, @date), 0) + @@DATEFIRST- 7) - 1
  DECLARE @dateDayOfWeek INT = DATEPART(WEEKDAY, DATEADD(DAY, @@DATEFIRST- 7, @date)) - 1

  RETURN @normalizedWeekOfYear + 
    CASE
      WHEN @jan1DayOfWeek < @dateFirst AND @dateDayOfWeek >= @dateFirst THEN 1
      WHEN @jan1DayOfWeek >= @dateFirst AND @dateDayOfWeek < @dateFirst THEN -1
      ELSE 0
    END
END
GO

然后,执行以下语句将分别返回 35 和 36:

SELECT dbo.Week('2013-08-28', 2)
SELECT dbo.Week('2013-08-28', 3)

【讨论】:

    【解决方案3】:
    /*
    不管@@DATEFIRST 是怎样的
    返回结果为
    工作日名称,工作日编号
    莫1
    涂2
    3
    4
    法郎 5
    萨6
    苏7
    */
    
    创建函数 dbo.fnFixWeekday
    (
        @currentDate 日期
    )
    返回整数
    作为
    开始
        -- 获取 DATEFIRST 设置
        声明 @ds int = @@DATEFIRST
        -- 获取当前 DATEFIRST 设置下的星期几
        声明@dow int = DATEPART(dw,@currentDate)
    
        返回 1+(((@dow+@ds) % 7)+5) % 7
    
    结尾
    

    【讨论】:

    • 这不能回答我的问题。要求是函数必须将一周的第一天作为参数之一。
    猜你喜欢
    • 2011-11-02
    • 2017-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-22
    • 1970-01-01
    • 2020-06-04
    • 1970-01-01
    相关资源
    最近更新 更多