Isoweek in SQL Server 2005

后端 未结 4 1560
天涯浪人
天涯浪人 2020-11-29 07:53

In SQL Server 2008 the isoweek can be found with this:

SELECT datepart(iso_week, getdate())

Before SQL Server 2008 there were no built-in f

相关标签:
4条回答
  • 2020-11-29 08:04

    I needed something similar for PowerQuery & PowerBI and based on t-clausen.dk's response I was able to make this equation. It works the same as his but uses PowerQuery syntax. Also the base date for the DATEDIFF of 0 was 1/1/1900 in SQL but in PowerQuery it is 12/30/1899 so I use 2 instead of the 0.

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

    I also needed the ISO Year so I made an adjustment to the ISO Week calculation and came up with:

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

    Change the [Date] to reference the date column in the data.

    0 讨论(0)
  • 2020-11-29 08:05

    Here's an approach that is similar to yours in that it also relies on this week's Thursday. But in the end it uses the date differently.

    1. Get the date of this (ISO) week's Thursday.

      Your own solution uses the hard coded date of a known Thursday. Alternatively, this week's Thursday could be found with the help of @@DATEFIRST:

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

      (I wasn't struggling too much for the right formula because it was already known to me.)

    2. Get the Thursday's day of year:

      SELECT DY = DATEPART(DAYOFYEAR, Th)
      
    3. Use the number to find out the week like this:

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

    Here are the above calculations in a single statement:

    SELECT ISOWeek = (DATEPART(DAYOFYEAR, Th) - 1) / 7 + 1
    FROM (
      SELECT Th = DATEADD(DAY, 3 - (DATEPART(WEEKDAY, @date) + @@DATEFIRST - 2) % 7, @date)
    ) s;
    
    0 讨论(0)
  • 2020-11-29 08:10

    Wow! Very good topic and solution to avoid using "set datefirst 1". I just want to add something. If like me, you also want to return the year with the ISO week, like "2015-01" as being "Year 2015, Week 01", it might be useful for reporting purpose. Since the year from ISO week can be different from the actual year of the date! Here is how I did in combination to your code.

    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
    

    Will return "2015-01".

    0 讨论(0)
  • 2020-11-29 08:17

    There is a link here for other earlier attempts http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=60510

    This is the OLD code for the function

    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
    

    After combining @AndriyM 's brilliant answer with my own, we are down to 1 line. This is the NEW code.

    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
    

    Explanation for the old code (not going to explain the new code. It is fragments from my code and AndriyM's code):

    Finding weekday 4 of the chosen date

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

    Finding isoyear - year of weekday 4 of a week is always the same year as the isoyear of that week

    datediff(yy, 0, day4)
    

    When adding 3 days to the first day of the isoyear a random day of the first isoweek of the isoyear is found

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

    finding relative week of the first isoweek of the isoyear

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

    Finding the monday minus 4 days of the first isoweek results in thursday of the week BEFORE the first day of the first isoweek of the isoyear

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

    Knowing first thursday of the week before the first isoweek and first thursday of the chosen week, makes it is quite easy to calculate the week, it doesn't matter which setting datefirst has since the weekdays of both dates are thursdays.

    datediff(ww, dateadd(ww, datediff(d, 0, dateadd(yy, datediff(yy, 0, day4),3))/7,-4),day4)
    
    0 讨论(0)
提交回复
热议问题