sqlalchemy FULL OUTER JOIN

时间:2013-12-03 20:28:41

标签: 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)
)

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

2 个答案:

答案 0 :(得分:7)

首先,sqlalchemy不支持FULL JOIN开箱即用,并且出于某些原因。所以提出的任何解决方案都将包含两部分:

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

    现在,出于避免FULL JOIN的原因,请阅读一些旧博客Better Alternatives to a FULL OUTER JOIN。 在这篇博客中,我将通过向缺失的列添加FULL JOIN值并在{{1上聚合(0)来了解如何避免 SUM的想法intead。 SA代码可能如下所示:

    UNION ALL

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

    • 只需单独执行这两个查询,然后在Python本身中聚合结果(对于不那么大的结果集)
    • 鉴于它看起来像某种报告功能而非业务模型工作流,​​请创建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) 查询并直接通过SQL执行。 (虽然它的表现确实好得多)

答案 1 :(得分:4)

从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
)

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