说我有一个像这样结构的表:
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一起使用的派生物。它支持我需要使用的大多数标准功能。
答案 0 :(得分: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
然而,对于数百万或行,它可能会非常慢。
答案 1 :(得分:1)
假设:
我会在Oracle SQL中写这个,因为那是我正在使用的,你没有指定;)
查询摘要:
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;
答案 2 :(得分: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;
上面的代码没有经过测试 - 但是,只是强调使用窗口函数。