私は最近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を使用しています。
これは動作するはずです(異なる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は「列」を表します
前の答えは機能しますが、要求した正確な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)
)