2016-11-22 11 views
0

私はパワーメータからの読みを格納するPostgreSQLのテーブルを持っています。 SQLAlchemyとpsycopg2を使ってデータベースに問い合わせます。いくつかの大規模なサイトでは、複数の電力計を持つことができる、と私は施設によって集計タイムスタンプ付きのデータを返すクエリを、持っている:SQLAlchemyのクエリ結果を含むユニオンサマリー統計?

生テーブル:集約

timestamp | meter_id | facility_id | reading 
    1:00:00 |  1 |   1 |  1.0 
    1:00:00 |  2 |   1 |  1.5 
    1:00:00 |  3 |   2 |  2.1 
    1:00:30 |  1 |   1 |  1.1 
    1:00:30 |  2 |   1 |  1.6 
    1:00:30 |  3 |   2 |  2.2 

timestamp | facility_1 | facility_2 
    1:00:00 |  2.5 |  2.1 
    1:00:30 |  2.7 |  2.2 

私が使用したクエリこれは次のようになります。

SELECT 
    reading.timestamp, 
    sum(reading.reading) FILTER (WHERE reading.facility_id = 1) as facility_1, 
    sum(reading.reading) FILTER (WHERE reading.facility_id = 2) as facility_2 
FROM reading 
GROUP BY reading.timestamp 
WHERE 
    reading.timestamp >= 1:00:00 AND reading.timestamp < 1:01:00 
    AND reading.facility_id IN 1, 2 

(ご迷惑をおかけして申し訳ありませんが、私は明確にするために少し問題があります)。私はしばしば表示のためにデータをダウンサンプリングする必要があります。これは上記のクエリをFROM ... AS ...節にラップし、データをより長い時間間隔でビニングすることによって行います。しかし、その前に、this blog postに記載されているのと同様に、私の派生した「施設」テーブルから、最小読み取り、最大読み取り、平均読み取りなどの要約統計量を取得したいと考えています。しかし、私はこのデータを取得するためにSQLALchemyを使用する方法を理解できません - 結果のSQLからpsycopg2エラーが発生し続けます。上記のクエリのマイSQLAlchemyのバージョンは次のとおりです。

selects = [Reading.timestamp, 
    sqlalchemy.func.sum(Reading.reading).filter(Reading.facility_id==1), 
    sqlalchemy.func.sum(Reading.reading).filter(Reading.facility_id==2) 
] 
base_query = db.session.query(*selects). \ 
    group_by(Reading.timestamp). \ 
    filter(Reading.facility_id.in_([1, 2])). \ 
    filter(and_(Reading.timestamp>=start_time, Reading.timestamp<=end_time)). \ 
    order_by(Reading.timestamp) 

私はこのようなもので要約統計量を得ることができます。私の元のクエリからのすべての列の平均で単一の行を返します

subq = base_query.subquery() 
avg_selects = [sqlalchemy.func.avg(col) for col in subq.columns] 
avg_query = db.session.query(*avg_selects) 

。しかし、私は元のクエリでこれをどうやって得るのか分かりません。別々に統計を取得する必要があります。これらのクエリは膨大な浪費のように感じられます。常にエラーを返す以下のようなクエリ:私はSQLAlchemyののサブクエリシステムの私の理解のように感じる

all = base_query.union(avg_query).all() 

ProgrammingError: (psycopg2.ProgrammingError) syntax error at or near "UNION" 
LINE 4: ...reading.timestamp ORDER BY reading.timestamp UNION SELE... 

は弱いですが、私はSQLAlchemyののドキュメントのサブクエリのチュートリアルからの前進を作ることができていません。アイデア?

答えて

0

答えはエラーメッセージです。サブクエリからORDER BY句をユニオン操作の外に削除し、UNION外に移動する必要がありました。私は要約統計量にダミーのタイムスタンプを使用して、タイムスタンプを注文した後に予測可能な順序でクエリー結果の先頭にあることを確認しています。次のコードが動作します。

from sqlalchemy.sql import expression, func 
from datetime import datetime 
from models import Reading 

selects = [Reading.timestamp.label("timestamp_"), 
    func.sum(Reading.reading).filter(Reading.facility_id==1), 
    func.sum(Reading.reading).filter(Reading.facility_id==2) 
] 

base_query = db.session.query(*selects). \ 
    group_by(Reading.timestamp). \ 
    filter(Reading.facility_id.in_([1, 2])). \ 
    filter(and_(Reading.timestamp>=start_time, Reading.timestamp<=end_time)) 

subq = base_query.subquery() 

avg_selects = [expression.bindparam('dummy_date', datetime(1980, 1, 1)).label("timestamp_") 
avg_selects += [func.avg(col) for col in subq.columns[1:] 
avg_query = db.session.query(*avg_selects) 

full_query = base_query.union(avg_query).order_by(asc("timestamp_")) 

私はこれを達成するためのより優雅な方法を聞いてうれしいです。クエリは、施設IDの任意のリストを取る関数でラップされます。 「列」トリックは、(最初​​の列が常にタイムスタンプである限り)任意の列で動作させるためにわかった唯一の方法です。

関連する問題