Следующий сценарий представляет собой выход в единообразно: она показывает даты начала и окончания периода, а также общее количество за период.
Это также определило способы нахождения значений для группировки. В принципе, вы можете видеть три разных шаблона: один для частоты 'day'
, другой для 'week'
и еще один для всех других типов частот.
Первый простейший: как PeriodStart, так и PeriodEnd - это только Date
.
В течение нескольких недель я использую довольно известный трюк, в соответствии с которым первый день недели выводится из заданной даты, вычитая из него значение, которое на один меньше, чем его день недели. Конец недели встречается аналогично: мы просто добавляем 6
к тому же выражению.
Месяцы, четверти и годы сгруппированы следующим образом. Целое число соответствующих единиц между нулевой датой и указанной датой добавляется к нулевой дате. Это дает нам начало периода. Конец найден очень аналогично, только мы добавляем число, которое больше, чем разница. Это приводит к началу следующего периода, поэтому мы затем вычитаем один день, что дает нам правильную дату окончания.
SELECT
PeriodStart,
PeriodEnd,
Count = SUM(Count)
FROM (
SELECT
PeriodStart = CASE @Frequency
WHEN 'day' THEN Date
WHEN 'week' THEN DATEADD(DAY, 1 - DATEPART(WEEKDAY, Date), Date)
WHEN 'month' THEN DATEADD(MONTH, DATEDIFF(MONTH, 0, Date), 0)
WHEN 'quarter' THEN DATEADD(QUARTER, DATEDIFF(QUARTER, 0, Date), 0)
WHEN 'year' THEN DATEADD(YEAR, DATEDIFF(YEAR, 0, Date), 0)
END,
PeriodEnd = CASE @Frequency
WHEN 'day' THEN Date
WHEN 'week' THEN DATEADD(DAY, 7 - DATEPART(WEEKDAY, Date), Date)
WHEN 'month' THEN DATEADD(DAY, -1, DATEADD(MONTH, DATEDIFF(MONTH, 0, Date) + 1, 0))
WHEN 'quarter' THEN DATEADD(DAY, -1, DATEADD(QUARTER, DATEDIFF(QUARTER, 0, Date) + 1, 0))
WHEN 'year' THEN DATEADD(DAY, -1, DATEADD(YEAR, DATEDIFF(YEAR, 0, Date) + 1, 0))
END,
Count
FROM atable
WHERE Date BETWEEN @DateStart AND @DateEnd
) s
GROUP BY
PeriodStart,
PeriodEnd
EXEC spReport '1/1/2011', '12/31/2011', 'day'
:
PeriodStart PeriodEnd Count
----------- ---------- -----
2011-11-15 2011-11-15 6
2011-12-16 2011-12-16 9
2011-12-17 2011-12-17 2
2011-12-18 2011-12-18 5
EXEC spReport '1/1/2011', '12/31/2011', 'week'
:
PeriodStart PeriodEnd Count
----------- ---------- -----
2011-11-13 2011-11-19 6
2011-12-11 2011-12-17 11
2011-12-18 2011-12-24 5
EXEC spReport '1/1/2011', '12/31/2011', 'month'
:
PeriodStart PeriodEnd Count
----------- ---------- -----
2011-11-01 2011-11-30 6
2011-12-01 2011-12-31 16
EXEC spReport '1/1/2011', '12/31/2011', 'quarter'
:
PeriodStart PeriodEnd Count
----------- ---------- -----
2011-10-01 2011-12-31 22
EXEC spReport '1/1/2011', '12/31/2011', 'year'
:
PeriodStart PeriodEnd Count
----------- ---------- -----
2011-01-01 2011-12-31 22
Примечание: Из MSDN:
Избегайте использования sp_ при процедуре именования. Этот префикс используется SQL Server для обозначения системных процедур. Использование префикса может привести к разрыву кода приложения, если есть системная процедура с тем же именем. Для получения дополнительной информации см. Designing Stored Procedures (Database Engine).
Это будет работать только в случае, если срок меньше года. В противном случае он будет рассчитываться, например, с февраля 2013 года и февраля 2014 года. – Gh0sT