在窗口函数内过滤(超过...分区)?

时间:2013-07-21 03:50:53

标签: sql window-functions

我正在尝试使用sum()over(partition by),但在该求和中进行过滤。我的用例总结了每个产品一个月的最后12个月,所以:

ITEM    MONTH    SALES
Item A  1/1/2011     2
Item A  2/1/2011     5
Item A  3/1/2011     3
Item A  4/1/2011     7
Item A  5/1/2011    12
Item A  6/1/2011     8
Item A  7/1/2011     9
Item A  8/1/2011    15
Item A  9/1/2011     6
Item A  10/1/2011    7
Item A  11/1/2011   12
Item A  12/1/2011    1
Item A  1/1/2012     3
Item A  2/1/2012     4
Item A  3/1/2012     5
Item A  4/1/2012     6
Item A  5/1/2012     4
Item A  6/1/2012     8
Item A  7/1/2012     9
Item A  8/1/2012    12
Item A  9/1/2012    14
Item A  10/1/2012    8
Item A  11/1/2012   12
Item A  12/1/2012   16

然后返回:

ITEM      MONTH_BEGIN SALES TTM SALES
Item A    1/1/2012        3        87
Item A    2/1/2012        4        88
Item A    3/1/2012        5        87
Item A    4/1/2012        6        89

1/1/12的TTM销售额是1/1 / 11-12 / 1/11的总和

2 个答案:

答案 0 :(得分:6)

我就是这样做的Oracle Analytic Functions

SELECT
   "ITEM",
   TO_CHAR("MONTH", 'MM/DD/YYYY') AS "MONTH_BEGIN",
   "SALES",
   SUM("SALES") OVER (
    PARTITION BY 
       "ITEM" 
    ORDER BY 
       "MONTH" 
    RANGE BETWEEN 
       INTERVAL '12' MONTH PRECEDING
       AND 
       INTERVAL '1' MONTH PRECEDING
   ) AS "TTM_SALES"  
FROM
   "SALES"  
ORDER BY
   "MONTH";

Working SQLFiddle demo


这将计算一个窗口的求和函数,该窗口在当前行的月份之前12个月开始并在其前一个月结束。

我假设您不需要在where子句中过滤任何内容。如果你这样做,请小心。引用Oracle documentation

  

分析函数是查询中执行的最后一组操作   除了最后的ORDER BY条款。在分析函数之前,所有联接和所有WHEREGROUP BYHAVING子句都已完成   处理。

因此,假设您只想显示 2012年第一季度的结果;如果您尝试通过在where子句中进行过滤来实现此目的,那么它也会影响TTM_SALES的累积结果(输出null37和{{1 }})。

这里的底线是:如果您需要在分析函数的窗口中过滤掉行,请将分析函数移动到子查询,并根据@peterm answer在外部查询中进行过滤:

12

答案 1 :(得分:1)

如果您对分析SUM()以外的任何其他内容持开放态度,那么这里有一个简单相关子查询的可能解决方案

SELECT s.item, s.month month_begin, s.sales,
       (SELECT SUM(sales) FROM sales 
         WHERE month BETWEEN DATEADD(month, -12, s.month) 
                         AND DATEADD(month,  -1, s.month)) ttm_sales
  FROM sales s 
 WHERE s.month BETWEEN '20120101' AND '20121201'

示例输出:

|   ITEM |                      MONTH_BEGIN | SALES | TTM_SALES |
-----------------------------------------------------------------
| Item A |   January, 01 2012 00:00:00+0000 |     3 |        87 |
| Item A |  February, 01 2012 00:00:00+0000 |     4 |        88 |
| Item A |     March, 01 2012 00:00:00+0000 |     5 |        87 |
| Item A |     April, 01 2012 00:00:00+0000 |     6 |        89 |
...

这是 SQLFiddle 演示