【问题标题】:SQL group by frequency within a date rangeSQL 按日期范围内的频率分组
【发布时间】:2012-01-28 05:38:32
【问题描述】:

我需要编写一个存储过程,它接受开始日期、结束日期和频率(日、周、月、季度、年)并根据这些参数输出结果集。显然,简单的部分是按日期范围查询,但是如何按频率分组呢?

所以如果有一组像这样的原始数据:

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', 'week'

我希望得到这样的结果:

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

这里有几个问题:

1) 我如何确定一周结束的日期(星期天结束的一周)?

2) 如何按 WeekOf 日期范围分组?

【问题讨论】:

    标签: sql-server tsql date-range


    【解决方案1】:
    select `date` as weekOf, sum(amt)
    from myTable
    where `date` between '2011-10-01' and '2012-01-01'
    group by week(`date` )
    

    【讨论】:

    • 哎呀才意识到这不是mysql
    【解决方案2】:

    以下脚本以统一的方式表示输出:它显示周期的开始和结束日期以及周期的总数。

    这也决定了查找要分组的值的方式。基本上,您可以看到三种不同的模式:一种用于 '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)

    【讨论】:

      【解决方案3】:

      这样的事情应该可以工作。

      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;
      

      【讨论】:

      • 这仅在期限少于一年时有效。否则,它将例如 2013 年 2 月和 2014 年 2 月一起计算。
      【解决方案4】:
       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))
      

      【讨论】:

        猜你喜欢
        • 2014-10-11
        • 2013-12-18
        • 1970-01-01
        • 2018-04-13
        • 2013-01-07
        • 1970-01-01
        • 2013-11-04
        • 2021-11-16
        相关资源
        最近更新 更多