计算所有条目的移动平均值

时间:2012-11-19 09:18:35

标签: sql oracle

我有一个表Measures,其中包含列:timestamp(Unix时间戳),tagvalue。 要获得15天的单一移动平均线,我可以做类似的事情:

SELECT tag,avg(value) 
FROM measures 
 WHERE tag='xtr' 
 AND timestamp<1353304800
 AND timestamp>1350622800 
 GROUP BY tag;

现在我想获得150个最新行的移动平均值,但我不确定如何查询它。

SELECT t, s,avg(bv) 
FROM 
  (SELECT A.timestamp as t,A.tag as ta,A.value as ac, B.timestamp as tb,B.value as bv, 
  FROM measures 
  CROSS JOIN measures B 
  WHERE A.tag='xtr' AND B.tag='xtr' 
  GROUP BY A.tag) WHERE ROWNUM <= 150;

这显然是错误的,但我一直在思考它并且无法弄明白。有任何想法吗? 我的思路是,我需要将每个条目与其下方的150个条目相匹配,并计算这150个条目的value平均值。我也很确定没有CROSS JOIN可能会有更好的方法,因为这样会很慢。

3 个答案:

答案 0 :(得分:6)

不完全清楚您的表结构和数据的唯一性,但此查询将为您提供所有时间戳的前150行(包括当前行)的真实移动平均值。

SELECT
  tag,
  timestamp,
  avg(value) over (partition by tag
                   order by timestamp asc
                   rows between 149 preceding and current row) moving_avg
FROM
  measures 
WHERE
  tag='xtr' 

如果您只需要隔离最近的150行,那么请将查询基于:

select
  tag,
  value
from(
  select tag
         value
  from measures
  order by timestamp desc)
where
  rownum <= 150

答案 1 :(得分:0)

WITH
  sequenced AS
(
  SELECT
    ROW_NUMBER() OVER (PARTITION BY tag ORDER BY timestamp) AS sequence_id,
    *
  FROM
    measures
)
SELECT
  measure.tag,
  measure.timestamp,
  AVG(history.value)
FROM
  sequenced           AS measure
INNER JOIN
  sequenced           AS history
    ON  history.tag          = measure.tag
    AND history.sequence_id >  measure.sequence_id - 150
    AND history.sequence_id <= measure.sequence_id
GROUP BY
  measure.tag,
  measure.timestamp

效率不高,每行都有150个其他行加入。但这是接近它的最简单方法,我知道大多数(相对较新的)版本的ORACLE都会支持。

答案 2 :(得分:0)

Oracle有包,使用包可以编写自己的移动平均功能。

我没有足够的时间来测试应用程序但理论上它应该可以工作(仅适用于oracle)

“在整个会话期间,套餐机构中声明的变量将存活(保持其价值)。”

Create or replace package xxx ;
procedure clearMovingAverage ;
function movingAverage (newAVG in number) return number ;
end ;
/

create or replace package body xxx ;
movTot number ;
movCnt number ;
procedure clearMovingAverage is 
begin
  movTot := 0 ;
  movCnt := 0 ;
end ;
function movingAverage (newAvg in number) return number is 
begin
  if newAvg is not null then 
     movTot := movTot + newAvg ;
     movCnt := movCnt + 1 ;
  end if ;
  return movTot / movCnt ;
end ;
end ;
/

用法:

begin
  xxx.clearMovingAverage ;
  select tag,xxx.movingAverage(avg(value)) 
    FROM measures 
  ..... 
   group by tag ;
end ;

begin
  xxx.clearMovingAverage ;
  select tag, xxx.MovingAverage(avgValue) 
    from (select tag,avg(value) avgValue 
          FROM measures 
          ..... 
          group by tag)
end ;

希望这段代码有用......