SQL Server не показывает правильные номера недель для данной даты

SQL Server показывает неделю 53 для первой недели 2011 года, кроме 1 января, и должна быть неделей 1.

Ниже приведен запрос и вывод:

declare @T table (dt datetime)
insert into @T values
('2010-12-26'),
('2010-12-27'),
('2010-12-28'),
('2010-12-29'),
('2010-12-30'),
('2010-12-31'),
('2011-01-01'),
('2011-01-02'),
('2011-01-03'),
('2011-01-04'),
('2011-01-05'),
('2011-01-06'),
('2011-01-07'),
('2011-01-08')
select dt,DATEPART(wk,dt) from @T

Выход:

2010-12-26 00:00:00.000 53
2010-12-27 00:00:00.000 53
2010-12-28 00:00:00.000 53
2010-12-29 00:00:00.000 53
2010-12-30 00:00:00.000 53
2010-12-31 00:00:00.000 53
2011-01-01 00:00:00.000 1
2011-01-02 00:00:00.000 2
2011-01-03 00:00:00.000 2
2011-01-04 00:00:00.000 2
2011-01-05 00:00:00.000 2
2011-01-06 00:00:00.000 2
2011-01-07 00:00:00.000 2
2011-01-08 00:00:00.000 2

Я хочу, чтобы SQL Server показывал первую неделю с 26 декабря по 1 января. Кто-нибудь знает, как это сделать?

Спасибо и с уважением, Ашвин.


person Aschwin    schedule 26.08.2011    source источник


Ответы (4)


Это было намного сложнее, чем я сначала ожидал. Я сравниваю конец прошлого года, чтобы увидеть, подходит ли он для того, чтобы стать частью нового года. Если это так, я устанавливаю неделю как 1, в противном случае я просто использую обычную неделю.

declare @T table (dt datetime) 
insert into @T values 
('2010-12-25'), 
('2010-12-26'), 
('2010-12-27'), 
('2010-12-28'), 
('2010-12-29'), 
('2010-12-30'), 
('2010-12-31'), 
('2011-01-01'), 
('2011-01-02'), 
('2011-01-03'), 
('2011-01-04'), 
('2011-01-05'), 
('2011-01-06'), 
('2011-01-07'), 
('2011-01-08'), 
('2011-12-31'),
('2012-01-01')

select dt, 
week = case when dt + 6 - datediff(day, -1, dt) % 7 = dateadd(year, datediff(year,-1, dt), 0)
then 1 else datepart(week, dt) end from @t

Доказательство:

https://data.stackexchange.com/stackoverflow/q/110527/

person t-clausen.dk    schedule 26.08.2011

Я не уверен, что это справедливо для всех лет, (но похоже на это), но вы можете решить эту проблему, используя CASE.

SELECT  dt
        , CASE  WHEN DATEPART(wk, dt) <> 53 
                THEN DATEPART(wk, dt) 
                ELSE 1 
          END  
FROM    @T

Новая часть даты ISO_WEEK не применяется к запрошенным вами выходным данным.

person Lieven Keersmaekers    schedule 26.08.2011

Я создал 2 функции для решения этой проблемы 1) для получения первого или последнего дня недели 2) для получения номера недели или года

функция 1

    CREATE FUNCTION [dbo].[fn_GetDayOf]
(
    @Date datetime,
    --@FirstDayOfWeek int = 7,
    @Mode int =1
)
/*
    Mode 1: First Day Of Week
    Mode 2: Last Day Of Week
*/

RETURNS datetime
WITH EXECUTE AS CALLER
BEGIN
    Declare @Return datetime

    --SET DATEFIRST @FirstDayOfWeek

    IF @Mode = 1
    BEGIN
        select @Return = dateadd(day,-(datepart(weekday,@date)-1),convert(date,@date))
    END
    ELSE IF @Mode = 2
    BEGIN
        select @Return = dateadd(SECOND,-1,convert(datetime,dateadd(day,(datepart(weekday,@date)),convert(date,@date))))
    END
    ELSE
    BEGIN
        SET @Return = @Date
    END
    --SET DATEFIRST 7

    RETURN @Return
END

Функция 2

    CREATE FUNCTION [dbo].[fn_GetYearWeek]
(
    @Date datetime,
    --@FirstDayOfWeek int = 7,
    @Mode int =1
)
/*
    Mode 1 = Week Number
    Mode 2 = Year
*/
RETURNS INT
BEGIN
    declare @Return int
    IF @Mode = 1
    BEGIN
        select @Return = case when  datepart(week,[dbo].[fn_GetDayOf] (@Date,1)) <> datepart(week,[dbo].[fn_GetDayOf] (@Date,2)) then datepart(week,[dbo].[fn_GetDayOf] (@Date,1)) else datepart(week,[dbo].[fn_GetDayOf] (@Date,2)) end 
    END
    ELSE IF @Mode = 2
    BEGIN
        select @Return = case when  datepart(WEEK,[dbo].[fn_GetDayOf] (@Date,1)) <> datepart(week,[dbo].[fn_GetDayOf] (@Date,2)) then datepart(YEAR,[dbo].[fn_GetDayOf] (@Date,1)) else datepart(YEAR,[dbo].[fn_GetDayOf] (@Date,2)) end 
    END
    ELSE
    BEGIN
        SET @Return = -1
    END

    Return  @Return
END

Пример запуска

declare @T table (dt datetime) 
insert into @T values 
('2010-12-25'), 
('2010-12-26'), 
('2010-12-27'), 
('2010-12-28'), 
('2010-12-29'), 
('2010-12-30'), 
('2010-12-31'), 
('2011-01-01'), 
('2011-01-02'), 
('2011-01-03'), 
('2011-01-04'), 
('2011-01-05'), 
('2011-01-06'), 
('2011-01-07'), 
('2011-01-08'), 
('2011-12-31'),
('2012-01-01'),
('2012-01-02'),
('2012-12-31'),
('2013-01-01')

select 
    dt,
    datepart(week,dt),
    --case when  datepart(week,[dbo].[fn_GetDayOf] (dt,1)) <> datepart(week,[dbo].[fn_GetDayOf] (dt,2)) then datepart(week,[dbo].[fn_GetDayOf] (dt,1)) else datepart(week,[dbo].[fn_GetDayOf] (dt,2)) end 
    [dbo].[fn_GetYearWeek] (dt,1),
    [dbo].[fn_GetYearWeek] (dt,2)
from @T

результат:

person Raymond H    schedule 10.04.2013

Другой способ получить общее количество недель в текущем году:

DECLARE @LASTDAY DATETIME
DECLARE @weeks INT
SET @LASTDAY = DATEADD(ms,-3,DATEADD(yy,0,DATEADD(yy,DATEDIFF(yy,0,GETDATE())+1,0)))
SELECT @weeks = CASE DATEname(dw,@LASTDAY)

    WHEN 'MONDAY' THEN DATEPART(WK, DATEADD(wk,DATEDIFF(wk,7,@LASTDAY),5))
    WHEN 'TUESDAY' THEN DATEPART(WK, DATEADD(wk,DATEDIFF(wk,7,@LASTDAY),5))
    WHEN 'WEDNESDAY' THEN DATEPART(WK, DATEADD(wk,DATEDIFF(wk,7,@LASTDAY),5))
    ELSE DATEPART(WK, @LASTDAY)
END
select @weeks
person Amritpal Kaur    schedule 02.08.2013