2011-12-27 3 views
8

У меня есть требование написать хранимую процедуру, которая принимает дату начала, дату окончания и частоту (день, неделю, месяц, квартал, год) и выводит набор результатов на основе этих параметры. Очевидно, что простая часть - это запрос по диапазону дат, но как вы группируетесь по частоте?Группа SQL по частоте в диапазоне дат

Так что, если есть набор исходных данных, как это:

Date   Count 
--------------------- 
11/15/2011   6 
12/16/2011   9 
12/17/2011   2 
12/18/2011   1 
12/18/2011   4 

И я называю мой ХП, как это:

sp_Report '1/1/2011', '12/31/2011 », 'неделя'

Я бы ожидать результатов, как это:

WeekOf   Count 
--------------------- 
11/19/2011   6 
12/17/2011   11 
12/24/2011   5 

Есть несколько вопросов здесь:

1) Как определить дату окончания недели (неделя, заканчивающаяся в воскресенье)?

2) Как я могу группировать этот диапазон дат недели?

ответ

10

Следующий сценарий представляет собой выход в единообразно: она показывает даты начала и окончания периода, а также общее количество за период.

Это также определило способы нахождения значений для группировки. В принципе, вы можете видеть три разных шаблона: один для частоты '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).

0
Create procedure MyProc 
@startDate DateTime, 
@endDate DateTime, 
@freq varChar(5) 
As 

    If @freq = "day" 
     Select DateAdd(day, 0, datediff(day, 0, date)), Frequency, 
     Sum(Count) 
     From Table 
     Group By DateAdd(day, 0, datediff(day, 0, date)) 
    Else If @freq = "week" 
     Select DateAdd(week, 0, datediff(week, 0, date)), Frequency, 
     Sum(Count) 
     From Table 
     Group By DateAdd(week, 0, datediff(week, 0, date)) 
    Else If @freq = "Month" 
     Select DateAdd(Month, 0, datediff(Month, 0, date)), Frequency, 
     Sum(Count) 
     From Table 
     Group By DateAdd(Month, 0, datediff(Month, 0, date)) 
    Else If @freq = "Quarter" 
     Select DateAdd(Quarter, 0, datediff(Quarter, 0, date)), Frequency, 
     Sum(Count) 
     From Table 
     Group By DateAdd(Quarter, 0, datediff(Quarter, 0, date)) 
    Else If @freq = "Year" 
     Select DateAdd(Year, 0, datediff(Year, 0, date)), Frequency, 
     Sum(Count) 
     From Table 
     Group By DateAdd(Year, 0, datediff(Year, 0, date)) 
0

Нечто подобное должно работать.

select date_column, 
    sum(count) 
from @table 
where date_column between @start_date and @end_date 
group by case @frequency 
        when 'week' then datepart(week,date_column) 
        when 'year' then datepart(year,date_column) 
        when 'quarter' then datepart(quarter,date_column) 
        when ... 
     end; 
+0

Это будет работать только в случае, если срок меньше года. В противном случае он будет рассчитываться, например, с февраля 2013 года и февраля 2014 года. – Gh0sT

0
select `date` as weekOf, sum(amt) 
from myTable 
where `date` between '2011-10-01' and '2012-01-01' 
group by week(`date`) 
+0

Ой, просто понял, что это не mysql –

Смежные вопросы