SQL группа по частоте в диапазоне дат - PullRequest
8 голосов
/ 27 декабря 2011

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

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

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

И я называю свой сохраненный процесс следующим образом:

sp_Report '01.01.2011', '12/31/2011', 'week'

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

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

Здесь есть пара вопросов:

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

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

Ответы [ 4 ]

10 голосов
/ 27 декабря 2011

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

Это также определило способы поиска значений для группировки по,По сути, вы можете видеть три различных шаблона: один для частоты '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 для обозначения системных процедур.Использование префикса может привести к сбою кода приложения, если существует системная процедура с таким же именем.Для получения дополнительной информации см. Разработка хранимых процедур (компонент Database Engine) .

0 голосов
/ 12 апреля 2012
select `date` as weekOf, sum(amt)
from myTable
where `date` between '2011-10-01' and '2012-01-01'
group by week(`date` )
0 голосов
/ 27 декабря 2011

Как-то так должно работать.

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 голосов
/ 27 декабря 2011
 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))
...