SQLAlchemy - подзапрос в предложении WHERE
Я только что начал использовать SQLAlchemy, и у меня все еще возникают проблемы, обворачивающие некоторые из концепций.
Свернувшись к основным элементам, у меня есть две таблицы, подобные этой (это через Flask-SQLAlchemy):
class User(db.Model):
__tablename__ = 'users'
user_id = db.Column(db.Integer, primary_key=True)
class Posts(db.Model):
__tablename__ = '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.
Ответы
Ответ 1
Это должно работать (другой 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
Ответ 2
предыдущий ответ работает, но точный 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)
)