#sql-server #tsql #aggregate #aggregate-functions
#sql-server #tsql #агрегировать #агрегатные функции
Вопрос:
У меня есть таблица, полная ежедневных сводных данных, но мне иногда нужно извлекать еженедельные сводные данные и предоставлять информацию об увеличении или уменьшении. По этой причине я рассматривал возможность использования функции T-SQL DATEPART для получения информации о номере недели и году для дат.
Например, я могу получить следующую информацию, используя сегодняшнюю дату (9/11/2020):
@nowWeekNumber int = datepart(wk,@today), --yields 37
@nowYear int = datepart(year,@today), --yields 2020
Используя эту логику, я мог бы затем собрать информацию о записях, где год 2020, а номер недели 36, а затем я мог бы сравнить эти цифры, чтобы получить еженедельное увеличение / уменьшение. (Или, может быть, я бы сравнил недели 35 и 36, чтобы убедиться, что я имею дело с целыми неделями, но вы понимаете картину)
Однако, если дата 2021-01-03, это вернет 2021 год и номер недели, равный 2. Если я вычту неделю, я получу 2021 год и номер недели 1. Этот номер недели будет содержать только 1 и 2 января, потому что с 12/27 по 12/31 считаются 2020 годом, а номер недели 53 (даже если календарная неделя с 12/27 по 1/2).
Другими словами, я не думаю, что смогу использовать weekNumber для сбора еженедельных данных, хотя это было бы довольно удобно. Я знаю, что могу использовать функции DATEADD для получения начальной и конечной даты для последовательных недель, и затем я могу собирать сводные данные для записей между этими датами, но есть ли более удобный способ сделать это?
Комментарии:
1. Из вопроса не совсем ясно, каково определение недели для целей вашей отчетности. Всегда ли неделя начинается и заканчивается в один и тот же день (например, понедельник), или это может быть за семь дней до / после произвольной даты?
Ответ №1:
Почему бы вам не рассмотреть возможность использования dateDiff
в качестве ключевой функции? Как…
select dateDiff(wk, 0, getDate())
Возвращает одно целое число за всю неделю (6297 для '20200911'
) и :
select dateAdd(wk, dateDiff(wk, 0, getDate()), 0),
dateAdd(dd, 6, dateAdd(wk, dateDiff(wk, 0, getDate()), 0))
или
select dateAdd(wk, 6297, 0),
dateAdd(dd, 6, dateAdd(wk, 6297, 0))
выдает 1-й и последний день этой недели.
Комментарии:
1. Да, это то, где я сейчас нахожусь. Я могу вручную собрать даты начала и окончания для данной недели. Я просто подумал, что было бы удобнее собирать даты, где неделя равна xyz, и я почти могу это сделать, за исключением того, что логика разваливается для дат около 1 января. Я полагаю, я мог бы использовать некоторую логику в этом ответе, чтобы получить группу записей, где dateDiff(wk, 0, dateValue) = определенное значение.
Ответ №2:
Вы можете использовать DATEPART
но вместо wk вы можете использовать iso week. Тогда у вас не возникнет проблемы с разделением недели на 2. Для уверенности также используйте SET DATEFIRST
, чтобы точно определить, в какой день начинается неделя.
SET DATEFIRST 1; --use monday as first day of the week
SELECT datepart(iso_week,'2021-01-01');
SELECT datepart(iso_week,'2021-01-03');
SELECT datepart(iso_week,'2021-01-04');
Другой вариант — создать свою собственную таблицу календаря и присоединить ее к своей ежедневной таблице.
РЕДАКТИРОВАТЬ: для недели, начинающейся в воскресенье
SET DATEFIRST 7;
SELECT DATEPART(WEEK, DATEADD( DAY, 1-DATEPART(WEEKDAY,'2020-12-27'),'2020-12-27' ) )
SELECT DATEPART(WEEK, DATEADD( DAY, 1-DATEPART(WEEKDAY,'2020-12-28'),'2020-12-28' ) )
SELECT DATEPART(WEEK, DATEADD( DAY, 1-DATEPART(WEEKDAY,'2021-01-01'),'2021-01-01' ) )
SELECT DATEPART(WEEK, DATEADD( DAY, 1-DATEPART(WEEKDAY,'2021-01-02'),'2021-01-02' ) )
Комментарии:
1. похоже, у iso_week та же проблема. 1/3/2021 имеет номер iso_week равный 53, но более ранняя неделя с 27.12.2020 по 1/2/2021 имеет значения iso_week 52 и 53 соответственно.
2. На самом деле это другая проблема. Похоже, что DATEFIRST не влияет на isoweek. Я думаю, это имеет смысл, потому что это международный стандарт. Вот почему неделя iso всегда начинается в понедельник.
3. Другой вариант — затем взять номер недели первого дня недели (например, воскресенье) для всех дней этой недели. Нравится
DATEPART(WEEK, DATEADD( DAY,1 -DATEPART(WEEKDAY,'2020-12-27'),'2020-12-27' ) )