1

假设我有一个结构如下的表:

id     dt        val
a     1/1/2012   23
a     2/1/2012   24
a     6/1/2013   12
a     7/1/2013   56
b     1/1/2009   34
b     3/1/2009   78

每一个id都有dt一个月的形式和一个值。可能会缺少几个月,但永远不会有重复的月份。

我需要为每个数据点计算 12 个月的滚动平均值。例如,第四行是 (56+12)/12。第三行是 (12)/12。第二行将是 (24+23)/12 等。我需要确定给定 ID 的最大移动平均值的月份(和值)。

这是我什至可以在 SQL 本身中做的事情,还是我需要导出数据集并使用其他方法?有数百万行,所以如果可以的话,我想用 SQL 来做。我查看了一些 MA 方法,但不确定它们是否适用于我正在尝试做的事情。

我使用的 SQL 是与 Teradata 一起使用的衍生产品。它支持我需要使用的大多数标准功能。

4

3 回答 3

4

只需使用子查询作为表达式:

SELECT id, 
       dt, 
       val, 
       (
        SELECT SUM(val)/12 
        FROM mytable t2 
        WHERE t2.id = t.id
          AND t2.dt > DATEADD(mm, -12, t.dt) 
          AND t2.dt < t.dt
       ) val12MonthAvg 
FROM mytable t

但是,对于数百万或行,它可能会非常慢。

于 2013-08-01T20:18:56.440 回答
1

假设:

  • 您的日期格式是 m/d/yyyy(我使用格式 mm/dd/yyyy)
  • 此表上的 id 是某个其他实体的 FK,其中 id 是 PK
  • 您应该获取所选行的日期,并查找该行以及该 ID 小于 12 个月的所有行,并将这些行中的 val 相加

我将在 Oracle SQL 中编写此代码,因为这是我正在使用的,而您没有指定;)

查询摘要:

  • “选择”是您的表的实例,用作输入行
  • “回溯”收集所有行,包括您选择的行和最多 12 个月前减去 1 天
  • 总结lookback.val的答案
WITH DateTable
      AS (SELECT 'a' id, TO_DATE ('01/01/2012', 'mm/dd/yyyy') dt, 23 val FROM DUAL
            UNION
            SELECT 'a', TO_DATE ('1/1/2012', 'mm/dd/yyyy'), 23 FROM DUAL
            UNION
            SELECT 'a', TO_DATE ('02/01/2012', 'mm/dd/yyyy'), 24 FROM DUAL
            UNION
            SELECT 'a', TO_DATE ('06/01/2013', 'mm/dd/yyyy'), 12 FROM DUAL
            UNION
            SELECT 'a', TO_DATE ('07/01/2013', 'mm/dd/yyyy'), 56 FROM DUAL
            UNION
            SELECT 'b', TO_DATE ('01/01/2009', 'mm/dd/yyyy'), 34 FROM DUAL
            UNION
            SELECT 'b', TO_DATE ('03/01/2009', 'mm/dd/yyyy'), 78 FROM DUAL)
SELECT chosen.id, chosen.dt, SUM (lookback.val)/12
  FROM DateTable chosen, DateTable lookback
 WHERE   chosen.id = 'a' --your input id
         AND chosen.dt = TO_DATE ('07/01/2013', 'mm/dd/yyyy') --your input date
         AND chosen.id = lookback.id
         AND lookback.dt > ADD_MONTHS (chosen.dt, -12)
         AND lookback.dt <= chosen.dt
GROUP BY chosen.id, chosen.dt;

如果您想查询任何行中不存在的日期/月份,请执行以下操作:

WITH DateTable
      AS (SELECT 'a' id, TO_DATE ('01/01/2012', 'mm/dd/yyyy') dt, 23 val FROM DUAL
            UNION
            SELECT 'a', TO_DATE ('1/1/2012', 'mm/dd/yyyy'), 23 FROM DUAL
            UNION
            SELECT 'a', TO_DATE ('02/01/2012', 'mm/dd/yyyy'), 24 FROM DUAL
            UNION
            SELECT 'a', TO_DATE ('06/01/2013', 'mm/dd/yyyy'), 12 FROM DUAL
            UNION
            SELECT 'a', TO_DATE ('07/01/2013', 'mm/dd/yyyy'), 56 FROM DUAL
            UNION
            SELECT 'b', TO_DATE ('01/01/2009', 'mm/dd/yyyy'), 34 FROM DUAL
            UNION
            SELECT 'b', TO_DATE ('03/01/2009', 'mm/dd/yyyy'), 78 FROM DUAL),
     InputData
      AS (SELECT 'b' id, TO_DATE ('12/15/2009', 'mm/dd/yyyy') dt FROM DUAL)
SELECT InputData.id, InputData.dt, SUM (lookback.val)/12
  FROM DateTable lookback, InputData
 WHERE  lookback.id = InputData.id
    AND lookback.dt > ADD_MONTHS (InputData.DT, -12)
    AND lookback.dt <= InputData.DT
     GROUP BY InputData.id, InputData.dt;
于 2013-08-01T20:39:58.943 回答
0

我认为您应该看看 Teradata 中的 Windowing 函数。(注意:所有最新的 ANSI SQL 投诉数据库都支持窗口函数,以使用户能够处理逐行操作,而不是基于集合的操作)。

所以,使用窗口函数我会写这样的东西:

SELECT ID ,DT ,VAL ,(SUM(VAL)OVER(PARTITION BY YEAR(DT)) )/12.00 AS L12M_mov_avg FROM some.table;

上面的代码没有经过测试——但是,只是为了突出窗口函数的使用。

于 2013-08-04T20:11:16.930 回答