sqlalchemy FULL OUTER JOIN

use*_*592 6 python sqlalchemy

如何在orm级别的sqlalchemy中实现FULL OUTER JOIN.

这是我的代码:

q1 = (db.session.query(
        tb1.user_id.label('u_id'),
        func.count(tb1.id).label('tb1_c')
    )
    .group_by(tb1.user_id)
)
q2 = (db.session.query(
        tb2.user_id.label('u_id'),
        func.count(tb2.id).label('tb2_c')
    )
    .group_by(tb2.user_id)
)
Run Code Online (Sandbox Code Playgroud)

以上两个查询,我想对它们应用FULL OUTER JOIN.

van*_*van 8

首先,sqlalchemy不支持FULL JOIN开箱即用,并且有一些很好的理由.因此,提出的任何解决方案将包括两部分:

  1. 缺少功能的解决方法
  2. sqlalchemy为该解决方案构建查询的语法

现在,出于避免这种情况的原因FULL JOIN,请阅读一些旧的博客更好的替代方案以进行全面的联接.从这篇博客中我将了解如何通过向缺少的列添加值和在intead 上聚合()来避免 .SA代码可能如下所示:FULL JOIN0SUMUNION ALL

q1 = (session.query(
        tb1.user_id.label('u_id'),
        func.count(tb1.id).label('tb1_c'),
        literal(0).label('tb2_c'), # @NOTE: added 0
      ).group_by(tb1.user_id))
q2 = (session.query(
        tb2.user_id.label('u_id'),
        literal(0).label('tb1_c'), # @NOTE: added 0
        func.count(tb2.id).label('tb2_c')
      ).group_by(tb2.user_id))

qt = union_all(q1, q2).alias("united")
qr = select([qt.c.u_id, func.sum(qt.c.tb1_c), func.sum(qt.c.tb2_c)]).group_by(qt.c.u_id)
Run Code Online (Sandbox Code Playgroud)

编写完上面的查询后,我实际上可能会考虑其他选项:

  • 只需单独执行这两个查询并在Python本身中聚合结果(对于不那么大的结果集)
  • 鉴于它看起来像某种报告功能而不是业务模型工作流,​​创建一个SQL查询并直接通过它执行engine.(只有当它真的表现得更好)

  • 从1.1版开始,sqlalchemy实际上支持完全外连接.请注意,如果您的sql引擎不支持完全外连接(例如,mysql),则构造的查询可能不起作用http://docs.sqlalchemy.org/en/latest/orm/query.html#sqlalchemy.orm .query.Query.join.params.full (6认同)

小智 8

从 1.1. sqlalchemy 现在完全支持 FULL OUTER JOINS。请参阅此处:https : //docs.sqlalchemy.org/en/13/orm/query.html#sqlalchemy.orm.query.Query.join.params.full

因此,对于您的代码,您需要执行以下操作:

q1 = (db.session.query(
        tb1.user_id.label('u_id'),
        func.count(tb1.id).label('tb1_c')
    )
    .group_by(tb1.user_id)
).cte('q1')

q2 = (db.session.query(
        tb2.user_id.label('u_id'),
        func.count(tb2.id).label('tb2_c')
    )
    .group_by(tb2.user_id)
).cte('q2')

result = db.session.query(
    func.coalesce(q1.u_id, q2.u_id).label('u_id'),
    q1.tb1_c,
    q2.tb2_c
).join(
    q2,
    q1.u_id == q2.u_id,
    full=True
)
Run Code Online (Sandbox Code Playgroud)

请注意,与任何 FULL OUTER JOIN 一样,tb1_c并且tb2_c可能为 null,因此您可能希望对它们应用合并。