5

我正在尝试使用 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 SALES 是 1/1/11-12/1/11 的总和

4

2 回答 2

9

下面的查询显示了我将如何使用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";

工作 SQLFiddle 演示


这将在当前行的月份前 12 个月开始并在其前 1 个月结束的窗口上计算 sum 函数。

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

分析函数是查询中执行的最后一组操作,除了最后一个ORDER BY子句。在处理分析函数之前,所有连接和所有WHERE、、GROUP BY和子句都已完成。HAVING

因此,假设您只想显示2012 年第一季度的结果;如果您尝试通过在 where 子句中进行过滤来做到这一点,它也会影响TTM_SALES以及(输出null3和)7的累积结果。12

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

SELECT 
   "X"."ITEM",
   TO_CHAR("X"."MONTH", 'MM/DD/YYYY') AS "MONTH_BEGIN",
   "X"."SALES",
   "X"."TTM_SALES"
FROM
(
   SELECT
      "ITEM",
      "MONTH",
      "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"
) "X"
WHERE 
  EXTRACT(MONTH FROM "X"."MONTH") BETWEEN 1 AND 4
  AND EXTRACT(YEAR FROM "X"."MONTH") = 2012; 
于 2013-07-21T07:00:01.810 回答
3

如果您对分析以外的任何内容持开放态度,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'

样本输出:

| 项目 | MONTH_BEGIN | 销售 | TTM_销售 |
-------------------------------------------------- ---------------
| 项目 A | 2012 年 1 月 1 日 00:00:00+0000 | 3 | 87 |
| 项目 A | 2012 年 2 月 1 日 00:00:00+0000 | 4 | 88 |
| 项目 A | 2012 年 3 月 1 日 00:00:00+0000 | 5 | 87 |
| 项目 A | 2012 年 4 月 1 日 00:00:00+0000 | 6 | 89 |
...

这是SQLFiddle演示

于 2013-07-21T04:11:38.307 回答