web-dev-qa-db-ja.com

SQLAlchemy-WHERE句のサブクエリ

私は最近SQLAlchemyを使い始めましたが、まだいくつかの概念を頭で悩ましています。

基本的な要素に要約すると、次のような2つのテーブルがあります(これはFlask-SQLAlchemyを使用しています)。

class User(db.Model):
    __table= 'users'
    user_id = db.Column(db.Integer, primary_key=True)

class Posts(db.Model):
    __table= 'posts'
    post_id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('users.user_id'))
    post_time = db.Column(db.DateTime)

    user = db.relationship('User', backref='posts')

ユーザーとその最新の投稿(投稿のないユーザーを除く)のリストを照会するにはどうすればよいですか。 SQLを使用していた場合、次のようにします。

SELECT [whatever]
FROM posts AS p
    LEFT JOIN users AS u ON u.user_id = p.user_id
WHERE p.post_time = (SELECT MAX(post_time) FROM posts WHERE user_id = u.user_id)

だから、私は自分が望む効果を得るための「望ましい」SQLを正確に知っていますが、SQLAlchemyでそれを「適切に」表現する方法はわかりません。

編集:重要な場合は、SQLAlchemy 0.6.6を使用しています。

47
Chad Birch

これは動作するはずです(異なるSQL、同じ結果):

t = Session.query(
    Posts.user_id,
    func.max(Posts.post_time).label('max_post_time'),
).group_by(Posts.user_id).subquery('t')

query = Session.query(User, Posts).filter(and_(
    User.user_id == Posts.user_id,
    User.user_id == t.c.user_id,
    Posts.post_time == t.c.max_post_time,
))

for user, post in query:
    print user.user_id, post.post_id

Cは「列」を表します

52
sayap

前の答えは機能しますが、要求した正確なsqlも実際のステートメントと同じように記述されています。

print s.query(User, Posts).\
    outerjoin(Posts.user).\
    filter(Posts.post_time==\
        s.query(
            func.max(Posts.post_time)
        ).
        filter(Posts.user_id==User.user_id).
        correlate(User).
        as_scalar()
    )

必ずしも明らかではない「概念」は、サブクエリを「スカラー」として確立するためにas_scalar()が現在必要であるということだと思います(コンテキストから==を想定しているはずです)。

編集:確認済み、これはバグのある動作で、チケット#2190を完了しました。現在のヒントまたはリリース0.7.2では、as_scalar()が自動的に呼び出され、上記のクエリは次のようになります。

print s.query(User, Posts).\
    outerjoin(Posts.user).\
    filter(Posts.post_time==\
        s.query(
            func.max(Posts.post_time)
        ).
        filter(Posts.user_id==User.user_id).
        correlate(User)
    )
61
zzzeek