views:

6706

answers:

9

Is it possible to create an sql statement that selects the week number (NOT the day of week - or the day number in a week). I'm creating a view to select this extra information along with a couple of other fields and thus can not use a stored procedure. I'm aware that it's possible to create a UDF to do the trick, but if at all possible i'd rather only have to add a view to this database, than both a view and a function.

Any ideas? Also where i come from, the week starts monday and week 1 is the first week of the year with atleast 4 days.

Related:

How do I calculate the week number given a date?

+1  A: 

Looks like the DATEPART mssql function should help you out with ...

DATEPART(wk, ‘Jan 1, xxxx’) = 1

Well I'll be.. turns out there is a way to set the first day of the week, DATEFIRST

SET DATEFIRST 1 -- for monday

Update: Now I understand better, what the OP wants.. which is custom-logic for this. I don't think MSSQL would have functions with such rich level of customization. But I may be wrong... I think you'll have to roll your own UDF here...sorry

Gishu
No, Hojou is looking for the ISO Week Number (ISO 8601). That has to be solved with a UDF.
Jonas Lincoln
A: 

SELECT DATEPART( wk, 'enter the date over here' )

This will return you the week number of date entered in quotes

Samiksha
A: 

Thanks for the feedback.

My biggest problem here, as i see it is, that datepart(wk, date) doesn't follow the rules for determining the week number in my country. In .net i can use the GregorianCalendar which lets me both set the first day (like gishu showed with the datefirst - even though i can't set that in a view) and it lets me pick from a list of three different ways of finding the first week - in my case 'jan 1' is NOT always week 1 - sometimes it's the last week of the year. The rule is - the first week with atleast 4 days counts as week 1 (don't as me why :P) Or am i missing something?

Per Hornshøj-Schierbeck
ooh custom rules.. this looks like WORK. sorry but UDF it is then... i think
Gishu
If you can do it in .Net why don't you look at writing a managed stored procedure in .Net to do it? You can then call this from your SQL.
DoctaJonez
It adds complexity that we're trying to avoid in this project, but thanks for the comment :)
Per Hornshøj-Schierbeck
Try entering DateTime(2008,12,31) in the .NET Calendar. I get week 53 but according to ISO 8601 it should be week 1 (2009). I commented on it on http://msdn.microsoft.com/en-us/library/system.globalization.calendar.getweekofyear.aspx#CommunityContent
Jonas Elfström
A: 

Looks like datepart will get you part of the way there, but you'll have to adjust to get your correct week number, based on the day of week of Jan 1 of the given year. I'm not familiar enough with T-SQL to do that, but it should be possible. Pity there isn't a mode argument as in MySQL

ysth
+4  A: 

Be aware that there are differences in what is regarded the correct week number, depending on the culture. Week numbers depend on a couple of assumptions that differ from country to country, see Wikipedia article on the matter. There is an ISO standard (ISO 8601) that applies to week numbers.

The SQL server integrated DATEPART() function does not necessarily do The Right Thing. SQL Server assumes day 1 of week 1 would be January 1, for many applications that's wrong.

Calculating week numbers correctly is non-trivial, and different implementations can be found on the web. For example, there's an UDF that calculates the ISO week numbers from 1930-2030, being one among many others. You'll have to check what works for you.

This one is from the Books Online:

CREATE FUNCTION ISOweek  (@DATE DATETIME)
RETURNS INT
AS
BEGIN
   DECLARE @ISOweek INT
   SET @ISOweek = DATEPART(wk,@DATE) 
                  +1 
                  -DATEPART(wk,CAST(DATEPART(yy,@DATE) AS CHAR(4))+‘0104′)
   -– Special cases: Jan 1-3 may belong to the previous year
   IF (@ISOweek=0)
      SET @ISOweek = dbo.ISOweek(CAST(DATEPART(yy,@DATE) - 1
                     AS CHAR(4))+‘12′+ CAST(24+DATEPART(DAY,@DATE) AS CHAR(2)))+1
   -– Special case: Dec 29-31 may belong to the next year
   IF ((DATEPART(mm,@DATE)=12) AND
      ((DATEPART(dd,@DATE)-DATEPART(dw,@DATE))>= 28))
      SET @ISOweek=1
   RETURN(@ISOweek)
END
GO
Tomalak
Thanks - i like the explicit information about the week numbers apart from the UDF - i think i'll solve it by creating a table with the weeknumbers (or first day of week 1) that i can do simple logic on in my view. The bad part is getting the extra table - but i think it beats a hard-to-read UDF ;)
Per Hornshøj-Schierbeck
But if you would check if the UDF does it - it will be faster than an extra table (if that matters for you), and you would not have to read it very often either. ;-) As I said, there are other implementations out there if you don't like/cannot use this one.
Tomalak
I would think calling this udf would take longer than a join in an indexed date/week table? I could be wrong, but focus on this task is keeping complexity low (everybody knows how to do an inner join, but not everyone would understand this udf). Thanks for bringing it up - i might have to test it ;)
Per Hornshøj-Schierbeck
Since the UDF is just doing basic math with no IO *at all*, it will be faster than any join. And calling/using it is as simple as calling a normal function ("SELECT dbo.ISOweek(MyDateTime)"), you might even add it to the master DB to have it available on the whole server.
Tomalak
+8  A: 

You need the ISO week. From http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=60510, here's an implementation:

drop function dbo.F_ISO_WEEK_OF_YEAR
go
create function dbo.F_ISO_WEEK_OF_YEAR
    (
    @Date datetime
    )
returns  int
as
/*
Function F_ISO_WEEK_OF_YEAR returns the
ISO 8601 week of the year for the date passed.
*/
begin

declare @WeekOfYear  int

select
    -- Compute week of year as (days since start of year/7)+1
    -- Division by 7 gives whole weeks since start of year.
    -- Adding 1 starts week number at 1, instead of zero.
    @WeekOfYear =
    (datediff(dd,
    -- Case finds start of year
    case
    when NextYrStart <= @date
    then NextYrStart
    when CurrYrStart <= @date
    then CurrYrStart
    else PriorYrStart
    end,@date)/7)+1
from
    (
    select
     -- First day of first week of prior year
     PriorYrStart =
     dateadd(dd,(datediff(dd,-53690,dateadd(yy,-1,aa.Jan4))/7)*7,-53690),
     -- First day of first week of current year
     CurrYrStart =
     dateadd(dd,(datediff(dd,-53690,aa.Jan4)/7)*7,-53690),
     -- First day of first week of next year
     NextYrStart =
     dateadd(dd,(datediff(dd,-53690,dateadd(yy,1,aa.Jan4))/7)*7,-53690)
    from
     (
     select
      --Find Jan 4 for the year of the input date
      Jan4 = 
      dateadd(dd,3,dateadd(yy,datediff(yy,0,@date),0))
     ) aa
    ) a

return @WeekOfYear

end
go
Jonas Lincoln
Thanks, just needed this today. It's more correct than the accepted answer.
dverespey
@Jonas Lincoln that's correct
marco.ragogna
A: 

Hello, have you considered using the WEEK function?

This will get you the week of the year for the specified date that you pass in.

SELECT { fn WEEK(GETDATE()) } AS WeekNumber, { fn WEEK(CONVERT(DATETIME, '2008-01-01 00:00:00', 102)) } AS FirstWeekOfYear, { fn WEEK(CONVERT(DATETIME, '2008-12-31 00:00:00', 102)) } AS LastWeekOfYear

This outputs the following SQL2000 and SQL2005:

  • WeekNumber: 50
  • FirstWeekOfYear: 1
  • LastWeekOfYear: 53

I Hope this helps :)

DoctaJonez
It looks like it has the same problem DatePart(wk, getdate()) and will not work. SELECT { fn WEEK('2003-12-31') } AS WeekNumber gives me 53 which is wrong, since the correct week number is 1
Per Hornshøj-Schierbeck
+1  A: 

I tested both the output from Books Online and the one made by Michael from the SQLTeam Forum. Only the latter outputs the correct ISO 8601 / NEN 2772! I tested this for weeks starting at 1-1-2000.

Thanks Michael!

A: 

I agree, the answer given by Tomalak and listed here http://thomasianalytics.spaces.live.com/blog/cns!B6B6A40B93AE1393!551.entry does not give accurate answers when comparing to examples listed on Wikipedia's IsoWeek page. Use the SqlTeam.com answer as given by Jonas Lincoln.

toxaq