Oracle:需要计算过去 3 个月的滚动平均值,其中我们每月提交的内容不止一份

tot*_*ian 3 sql oracle

我在 Oracle 中见过很多滚动平均值的例子,但确实达到了我想要的效果。

这是我的原始数据

DATE            SCORE   AREA
----------------------------
01-JUL-14       60      A
01-AUG-14       45      A
01-SEP-14       45      A
02-SEP-14       50      A
01-OCT-14       30      A
02-OCT-14       45      A
03-OCT-14       50      A
01-JUL-14       60      B
01-AUG-14       45      B
01-SEP-14       45      B
02-SEP-14       50      B
01-OCT-14       30      B
02-OCT-14       45      B
03-OCT-14       50      B
Run Code Online (Sandbox Code Playgroud)

这是我的滚动平均值所需的结果

MMYY        AVG     AREA
-------------------------
JUL-14      60      A
AUG-14      52.5    A
SEP-14      50      A
OCT-14      44      A
JUL-14      60      B
AUG-14      52.5    B
SEP-14      50      B
OCT-14      44      B
Run Code Online (Sandbox Code Playgroud)

我需要它工作的方式是,对于每个 MMYY,我需要回顾 3 个月的情况,以及每个部门的平均分数。例如,

对于 OCT 中的 A 区,从 10 月份开始的最后 3 个月,有 6 个研究,(45+45+50+30+45+50)/6 = 44.1

通常我会像这样编写查询

SELECT
  AREA, 
  TO_CHAR(T.DT,'MMYY') MMYY,
  ROUND(AVG(SCORE)
    OVER (PARTITION BY AREA ORDER BY TO_CHAR(T.DT,'MMYY') ROWS BETWEEN 2 PRECEDING AND CURRENT ROW),1)
    AS AVG 
    FROM T
Run Code Online (Sandbox Code Playgroud)

这将查看最近 3 个条目,而不是最近 3 个月

Gor*_*off 5

实现此目的的一种方法是将聚合函数与分析函数混合。平均值的关键思想是避免使用avg(),而是除以sum()a count(*)

  SELECT AREA, TO_CHAR(T.DT, 'MMYY') AS MMYY,
         SUM(SCORE) / COUNT(*) as AvgScore,
         SUM(SUM(SCORE)) OVER (PARTITION BY AREA ORDER BY MAX(T.DT) ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) / SUM(COUNT(*)) OVER (PARTITION BY AREA ORDER BY MAX(T.DT) ROWS BETWEEN 2 PRECEDING AND CURRENT ROW)
  FROM t
  GROUP BY AREA, TO_CHAR(T.DT, 'MMYY') ;
Run Code Online (Sandbox Code Playgroud)

请注意该order by条款。如果您的数据跨越数年,那么使用 MMYY 格式会带来问题。最好使用 YYYY-MM 等月份格式,因为字母顺序与自然顺序相同。