簡體   English   中英

如何在SQLAlchemy中使用子查詢來生成移動平均線?

[英]How to use subqueries in SQLAlchemy to produce a moving average?

我的問題是我想要檢索測量列表以及這些測量的移動平均值。 我可以用這個SQL語句(postgresql interval語法)來做到這一點:

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子句?

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

是的,顯然我需要的是使用所謂的標量選擇 使用那些我得到這個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;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM