Isoweek在SQL Server 2005中

时间:2011-09-07 08:11:36

标签: sql-server-2005 tsql

在SQL Server 2008中可以找到isoweek:

SELECT datepart(iso_week, getdate())

在SQL Server 2008之前,没有内置函数可以找到isoweek。

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

由于问题很严重,我预计这个问题已经耗尽,并且找到了最佳解决方案。我虽然找不到好方法。

我写了一个解决方案,我将在稍后发布。但在此之前,我想确保没有其他人可以匹配我写的解决方案。

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

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

4 个答案:

答案 0 :(得分:36)

这里有其他早期尝试的链接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)

当在isoyear的第一天添加3天时,发现了isoyear的第一个isoweek的随机日

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

找到isoyear的第一个isoweek的相对周

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

找到第一个isoweek的星期一减去4天的结果是在第一个isoweek的第一天之前的星期四的星期四

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

在第一个isoweek之前的一周的第一周知道 在选定的一周的第一个星期四, 因为计算一周是很容易的,所以从两个日期的工作日是星期四以来,设置datefirst的日期并不重要。

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

答案 1 :(得分:13)

这是一种类似于你的方法,因为它也依赖于本周的周四。但最终它以不同的方式使用日期。

  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
    
  4. 以下是单一陈述中的上述计算:

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

答案 2 :(得分:1)

哇!非常好的主题和解决方案,以避免使用"设置datefirst 1"。我只想添加一些东西。如果像我一样,你也希望以ISO周回归年份,例如" 2015-01"作为" 2015年,第01周和第34周,它可能对报告目的有用。从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

将返回&#34; 2015-01&#34;。

答案 3 :(得分:0)

我需要类似的PowerQuery和amp; PowerBI并基于t-clausen.dk的响应,我能够制作出这个等式。它与他的工作方式相同,但使用的是PowerQuery语法。 DATEDIFF为0的基准日期是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]以引用数据中的日期列。