Проблема с группировкой по европейской стандартной неделе и году - PullRequest
3 голосов
/ 20 июля 2011

Имеется datepart iso_week, возвращающая iso_week для выбранного дня.

SELECT DATEPART (iso_week, getdate ())

Это вернет европейский стандарт для текущей недели.Это не обязательно то же самое, что и неделя.

А вот и хитрая часть:

SELECT DATEPART(iso_week, '2011-01-01')

Возвращает

52 

, поэтому он относится к прошлому году.по годам и iso_week мне нужно учесть, что iso_week не того же года.

Iso_week начинается в понедельник и относится к году, когда большинство дней перекрываются.Таким образом, 4 дня в 2010 году и 3 дня в 2011 году, неделя составляет 52, и все дни принадлежат iso_year 2010. Однако TSQL не имеет детектора iso_year.

declare @t table(col1 datetime)

insert @t 
ALL SELECT '2010-12-28'
UNION ALL SELECT '2010-12-29'
UNION ALL SELECT '2010-12-30'
UNION ALL SELECT '2010-12-31'
UNION ALL SELECT '2011-01-01'
UNION ALL SELECT '2011-01-02'
--UNION ALL SELECT '2011-01-03' Stackexchange is bugged and can't handle this line showing 53
UNION ALL SELECT '2011-01-04'

Мне нужно что-то вроде (iso_year hasnt существует):

SELECT DATEPART(ISO_WEEK, col1) WEEK, DATEPART(iso_YEAR, col1) YEAR, COUNT(*) COUNT 
FROM @t
GROUP BY DATEPART(ISO_WEEK, col1), DATEPART(iso_YEAR, col1)
ORDER BY  2,1

Ожидаемый результат

WEEK  YEAR          COUNT
52    2010           6
1     2011           2

Ответы [ 4 ]

3 голосов
/ 21 июля 2011

Четверг той же недели ISO даст вам точный год. И этот ответ может дать вам идею, как получить правильный четверг от указанной даты.

SELECT
  Week  = DATEPART(ISOWK, TheThursday),
  Year  = DATEPART(YEAR, TheThursday),
  Count = COUNT(*)
FROM (
  SELECT
    TheThursday = DATEADD(
      DAY,
      3 - (DATEPART(DW, col1) + @@DATEFIRST - 2) % 7,
      col1
    )
  FROM @t
) s
GROUP BY
  TheThursday
1 голос
/ 21 июля 2011

Edited ...

SELECT 
  IsoWeek  = DATEPART(ISO_WEEK, TheDate), 
  IsoYear  = CASE 
    WHEN 
      MONTH(TheDate) = 1 AND DATEPART(ISO_WEEK, TheDate) > 51 
      THEN YEAR(TheDate) - 1 
      ELSE YEAR(TheDate) 
    END, 
  DayCount = COUNT(*)
FROM 
  @t
GROUP BY 
  DATEPART(ISO_WEEK, TheDate), 
  CASE 
    WHEN MONTH(TheDate) = 1 AND DATEPART(ISO_WEEK, TheDate) > 51 
    THEN YEAR(TheDate) - 1 
    ELSE YEAR(TheDate) 
  END 
ORDER BY  
  IsoYear,
  IsoWeek

--IsoWeek  IsoYear  DayCount
--     52     2010         6
--      1     2011         2
1 голос
/ 21 июля 2011

Это решение также обрабатывает годы, когда неделя начинается годом ранее.

SELECT DATEPART(ISO_WEEK, col1) WEEK, 
DATEPART(year , col1 - CAST(col1-.5 as int)%7 + 3) YEAR, 
COUNT(*) COUNT 
FROM @t
GROUP BY DATEPART(ISO_WEEK, col1), 
DATEPART(year , col1 - CAST(col1-.5 as int)%7 + 3)
ORDER BY 2,1
1 голос
/ 20 июля 2011

Вы можете проверить по dayofyear и iso_week, чтобы выяснить, нужно ли вычитать год с 1 или нет.

select datepart(iso_week, col1) as [week], 
       case when datepart(dayofyear, col1) < 7 and
                 datepart(iso_week, col1) > 51
            then year(col1) - 1
            else year(col1)
       end as [year], 
       count(*) as [count]
from @t
group by datepart(iso_week, col1),
         case when datepart(dayofyear, col1) < 7 and
                   datepart(iso_week, col1) > 51
              then year(col1) - 1
              else year(col1)
         end
order by [year], [week]
...