2010-09-21 34 views
4

我的問題是,我想要檢索測量列表以及這些測量的移動平均值。我能做到這一點與這個SQL語句(PostgreSQL的間隔語法):如何在SQLAlchemy中使用子查詢來生成移動平均數?

SELECT time, value,     
    (
     SELECT AVG(t2.value) 
     FROM measurements t2 
     WHERE t2.time BETWEEN t1.time - interval '5 days' AND t1.time 
    ) moving_average 
FROM measurements t1 
ORDER BY t1.time; 

我想有SQLAlchemy的代碼產生了類似的聲明,以這種效果。目前,我有這個Python代碼:

moving_average_days = # configureable value, defaulting to 5 
t1 = Measurements.alias('t1') 
t2 = Measurements.alias('t2') 
query = select([t1.c.time, t1.c.value, select([func.avg(t2.c.value)], t2.c.time.between(t1.c.time - datetime.timedelta(moving_average_days), t1.c.time))], 
      t1.c.time > (datetime.datetime.utcnow() - datetime.timedelta(ndays))). \ 
     order_by(Measurements.c.time) 

也就是說然而,生成此SQL:

SELECT t1.time, t1.value, avg_1 
FROM measurements AS t1, 
    (
     SELECT avg(t2.value) AS avg_1 
     FROM measurements AS t2 
     WHERE t2.time BETWEEN t1.time - %(time_1)s AND t1.time 
    ) 
WHERE t1.time > %(time_2)s 
ORDER BY t1.time; 

這SQL有子查詢的FROM子句中的一部分在那裏可以不用的列值標訪問頂層值,即它會導致PostgreSQL的吐出這個錯誤:

ERROR: subquery in FROM cannot refer to other relations of same query level 
LINE 6:   WHERE t2.time BETWEEN t1.time - interval '5 days' AN... 

我會這樣想知道的是:如何獲取SQLAlchemy的子查詢移到SELECT clau SE?

或者另一種獲得移動平均線的方法(不對每個(時間,值)對執行查詢)將是一個選項。

回答

5

對,顯然我需要的是使用所謂的scalar select。通過使用那些我得到這個Python代碼,因爲我希望它實際上作品(生成相應的SQL來,在我的問題這是我的目標第一的):

moving_average_days = # configurable value, defaulting to 5 
ndays = # configurable value, defaulting to 90 
t1 = Measurements.alias('t1') ###### 
t2 = Measurements.alias('t2') 
query = select([t1.c.time, t1.c.value, 
        select([func.avg(t2.c.value)], 
         t2.c.time.between(t1.c.time - datetime.timedelta(moving_average_days), t1.c.time)).label('moving_average')], 
      t1.c.time > (datetime.datetime.utcnow() - datetime.timedelta(ndays))). \ 
     order_by(t1.c.time) 

這給出了這樣的SQL:

SELECT t1.time, t1.value, 
    (
     SELECT avg(t2.value) AS avg_1 
     FROM measurements AS t2 
     WHERE t2.time BETWEEN t1.time - :time_1 AND t1.time 
    ) AS moving_average 
FROM measurements AS t1 
WHERE t1.time > :time_2 ORDER BY t1.time; 
+0

你忘了在代碼中的某個地方調用.as_scalar()嗎? :) – Sudheer 2013-06-25 18:21:09

+0

我沒有在該代碼中的任何地方使用as_scalar,它(仍然)工作正常。另外SQL在PostgreSQL的命令行客戶端中輸入它時,也給了我想要的東西。 – Giel 2013-06-26 15:39:04