0

我有一个表, Measures, 列: timestamp(Unix 时间戳), tag, value. 要获得一个单一的移动平均线,比如 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 个条目进行匹配,并计算value这 150 个条目的平均值。我也很确定没有 a 可能有更好的方法CROSS JOIN,因为那会很慢。

4

3 回答 3

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
于 2012-11-19T10:08:44.640 回答
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 版本将支持的最简单的方法。

于 2012-11-19T09:54:08.130 回答
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 ;

希望这段代码会有所帮助...

于 2012-11-19T11:25:54.923 回答