【问题标题】:Isoweek in SQL Server 2005SQL Server 2005 中的等周线
【发布时间】:2011-09-07 08:11:35
【问题描述】:

在 SQL Server 2008 中,可以通过以下方式找到等周:

SELECT datepart(iso_week, getdate())

在 SQL Server 2008 之前,没有内置函数来查找等周。

我一直在寻找一个好的语法来寻找 SQL Server 2005 的用户定义 iso_week。我找到了很多解决方案。不喜欢我找到的任何解决方案,大多数都不起作用,而且它们太长了。

由于这个问题已经很老了,我希望这个问题已经解决了,并且已经找到了最佳解决方案。但是我找不到好的方法。

我写了一个解决方案,稍后我将发布。但在我这样做之前,我想绝对确定没有其他人能比得上我写的解决方案。

我希望获得自学者徽章。我敦促人们为这个古老的问题找到最好的答案。

在让人们有机会找到一个好的解决方案后,我将发布我的答案。

【问题讨论】:

  • 与周数一起包含 ISO 周年很重要,因为它可能与正常日期年不同。这似乎很重要。
  • @MicheldeRuiter 链接到 iso_year here
  • 我已经在那里找到了你的答案,很高兴让其他读者知道。

标签: sql-server-2005 tsql


【解决方案1】:

这里有其他早期尝试的链接http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=60510

这是函数的旧代码

CREATE function f_isoweek(@date datetime)
RETURNS INT
as
BEGIN
DECLARE @rv int

SELECT @rv = datediff(ww, dateadd(ww, datediff(d, 0, dateadd(yy, datediff(yy, 0, day4),3))/7,-4),day4)
FROM (SELECT dateadd(ww, datediff(day, 0, @date)/7, 3) day4) a

RETURN @rv
END

在将@AndriyM 的精彩答案与我自己的答案结合后,我们只剩下 1 行了。这是新代码。

CREATE function f_isoweek(@date datetime)
RETURNS INT
as
BEGIN

RETURN (datepart(DY, datediff(d, 0, @date) / 7 * 7 + 3)+6) / 7
-- replaced code for yet another improvement.
--RETURN (datepart(DY, dateadd(ww, datediff(d, 0, @date) / 7, 3))+6) / 7

END

旧代码解释(新代码不解释,是我的代码和AndriyM的代码的片段):

查找所选日期的第 4 个工作日

dateadd(week, datediff(day, 0, @date)/7, 3) 

查找等年 - 一周中第 4 个工作日的年份始终与该周的等年相同

datediff(yy, 0, day4)

当等年的第一天加上 3 天时,会发现等年的第一个等周的随机日

dateadd(yy, datediff(yy, 0, day4),3)

查找等年的第一个等周的相对周

datediff(d, 0, dateadd(yy, datediff(yy, 0, day4),3))/7

查找第一个等周的星期一减去 4 天的结果是在等年的第一个等周的第一天之前的一周的星期四

dateadd(ww, datediff(d, 0, dateadd(yy, datediff(yy, 0, day4),3))/7,-4)

知道第一个等周前一周的第一个星期四 以及所选周的第一个星期四, 使得计算星期非常容易,因为两个日期的工作日都是星期四,所以设置 datefirst 并不重要。

datediff(ww, dateadd(ww, datediff(d, 0, dateadd(yy, datediff(yy, 0, day4),3))/7,-4),day4)

【讨论】:

  • +1。与此版本相比,msdn.microsoft.com/en-us/library/ms186755.aspx 你的版本要好很多,因为它不依赖于set datefirst 1
  • 不错!我更喜欢你的(n + 6) / 7,而不是我的(n - 1) / 7 + 1。如果可以的话,我会再次投票。
  • 如果我想让我的星期从星期日开始怎么办?
  • @Martin iso 周不是从星期日开始
  • 这个公式很棒。非常感谢!
【解决方案2】:

这是一种与您的方法相似的方法,它也依赖于本周的星期四。但最终它使用不同的日期。

  1. 获取本 (ISO) 周星期四的日期。

    您自己的解决方案使用已知星期四的硬编码日期。或者,可以在@@DATEFIRST 的帮助下找到本周的星期四:

    SELECT Th = DATEADD(DAY, 3 - (DATEPART(WEEKDAY, @date) + @@DATEFIRST - 2) % 7, @date)
    

    (我并没有为正确的公式而苦苦挣扎,因为它对我来说是already known。)

  2. 获取一年中的星期四:

    SELECT DY = DATEPART(DAYOFYEAR, Th)
    
  3. 像这样使用数字找出星期:

    SELECT ISOWeek = (DY - 1) / 7 + 1
    

以下是单个语句中的上述计算:

SELECT ISOWeek = (DATEPART(DAYOFYEAR, Th) - 1) / 7 + 1
FROM (
  SELECT Th = DATEADD(DAY, 3 - (DATEPART(WEEKDAY, @date) + @@DATEFIRST - 2) % 7, @date)
) s;

【讨论】:

  • +1 太棒了,我花了一段时间才意识到你在做什么,到目前为止我认为你在作弊,我为什么没有想到这一点。我将我们的答案组合成一个非常简短的紧凑型解决方案。
  • 嗨 @AndriyM 你可能是少数能够欣赏this 的人之一 - 想象一下每周 8 天并使用相同的逻辑
  • @t-clausen.dk:仍在弄清楚逻辑的所有细节,但这太不可思议了。感谢分享!
  • 我要警告你,我为代码高尔夫提供的一些答案并不容易理解
  • @t-clausen.dk:没关系。当我无法理解其中任何一个时,我知道该向谁寻求帮助 :) 干杯!
【解决方案3】:

哇!避免使用“set datefirst 1”的非常好的主题和解决方案。我只是想补充一点。如果像我一样,您还想用 ISO 周返回年份,例如“2015-01”作为“2015 年,第 01 周”,它可能对报告有用。由于 ISO 周的年份可能与日期的实际年份不同!这是我结合您的代码所做的。

DECLARE @Date AS DATETIME
SET @Date = '2014-12-31'
SELECT 
       CAST(CASE WHEN MONTH(@Date) = 1 AND Q.ISOweek > 50 THEN YEAR(@Date) - 1
                 WHEN MONTH(@Date) = 12 AND Q.ISOweek < 3 THEN YEAR(@Date) + 1
                 ELSE YEAR(@Date)
            END
            AS VARCHAR(4))
    + '-'
    + RIGHT('00' + CAST(Q.ISOweek AS NVARCHAR(2)), 2) AS ISOweek
FROM (SELECT (datepart(DY, datediff(d, 0, @Date) / 7 * 7 + 3) + 6) / 7 AS ISOweek) Q

将返回“2015-01”。

【讨论】:

【解决方案4】:

对于 PowerQuery 和 PowerBI,我需要类似的东西,并且根据 t-clausen.dk 的回复,我能够得出这个等式。它与他的工作方式相同,但使用 PowerQuery 语法。此外,0 的DATEDIFF 的基准日期在 SQL 中是 1/1/1900,但在 PowerQuery 中是 12/30/1899,所以我使用 2 而不是 0。

ISO Week = Number.RoundDown((Date.DayOfYear(Date.From(Duration.Days(([Date]-Date.From(2))/7)*7+5))+6)/7)

我还需要 ISO 年,因此我对 ISO 周计算进行了调整并得出:

ISO Year = Date.Year(Date.From(Duration.Days(([Date]-Date.From(2))/7)*7+3))

更改[Date] 以引用数据中的日期列。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多