在SQLAlchemy中的子查询之间加入

时间:2015-01-16 18:16:21

标签: mysql sqlalchemy flask-sqlalchemy

关于我为这篇文章SQL Group By and Limit issue接受的答案,我需要弄清楚如何使用SQLAlchemy创建该查询。作为参考,我需要运行的查询是:

SELECT t.id, t.creation_time, c.id, c.creation_time
FROM (SELECT id, creation_time  
      FROM thread
      ORDER BY creation_time DESC
      LIMIT 5
     ) t
LEFT OUTER JOIN comment c ON c.thread_id = t.id
WHERE 3 >= (SELECT COUNT(1) 
            FROM comment c2 
            WHERE c.thread_id = c2.thread_id 
            AND c.creation_time <= c2.creation_time
           )

我有查询的前半部分,但我正在努力学习WHERE子句的语法以及如何将它与JOIN结合起来。有人有什么建议吗?

谢谢!

编辑:第一次尝试似乎搞乱了.filter()调用:

c = aliased(Comment)
c2 = aliased(Comment)

subq = db.session.query(Thread.id).filter_by(topic_id=122098).order_by(Thread.creation_time.desc()).limit(2).offset(2).subquery('t')

subq2 = db.session.query(func.count(1).label("count")).filter(c.id==c2.id).subquery('z')

q = db.session.query(subq.c.id, c.id).outerjoin(c, c.thread_id==subq.c.id).filter(3 >= subq2.c.count)

这将生成以下SQL:

SELECT t.id AS t_id, comment_1.id AS comment_1_id 
FROM (SELECT count(1) AS count 
FROM comment AS comment_1, comment AS comment_2 
WHERE comment_1.id = comment_2.id) AS z, (SELECT thread.id AS id 
FROM thread 
WHERE thread.topic_id = :topic_id ORDER BY thread.creation_time DESC
 LIMIT 2 OFFSET 2) AS t LEFT OUTER JOIN comment AS comment_1 ON comment_1.thread_id = t.id 
WHERE z.count <= 3

请注意,子查询排序不正确,并且subq2以某种方式从注释中选择两次。手动修复可以得到正确的结果,我只是不确定如何让SQLAlchemy做到正确。

1 个答案:

答案 0 :(得分:1)

试试这个:

c = db.aliased(Comment, name='c')
c2 = db.aliased(Comment, name='c2')

sq = (db.session
      .query(Thread.id, Thread.creation_time)
      .order_by(Thread.creation_time.desc())
      .limit(5)
      ).subquery(name='t')

sq2 = (
    db.session.query(db.func.count(1))
    .select_from(c2)
    .filter(c.thread_id == c2.thread_id)
    .filter(c.creation_time <= c2.creation_time)
    .correlate(c)
    .as_scalar()
)

q = (db.session
     .query(
         sq.c.id, sq.c.creation_time,
         c.id, c.creation_time,
     )
     .outerjoin(c, c.thread_id == sq.c.id)
     .filter(3 >= sq2)
     )