如何在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.
首先,sqlalchemy
不支持FULL JOIN
开箱即用,并且有一些很好的理由.因此,提出的任何解决方案将包括两部分:
sqlalchemy
为该解决方案构建查询的语法现在,出于避免这种情况的原因FULL JOIN
,请阅读一些旧的博客更好的替代方案以进行全面的联接.从这篇博客中我将了解如何通过向缺少的列添加值和在intead 上聚合()来避免 .SA代码可能如下所示:FULL JOIN
0
SUM
UNION 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)
编写完上面的查询后,我实际上可能会考虑其他选项:
SQL
查询并直接通过它执行engine
.(只有当它真的表现得更好)小智 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,因此您可能希望对它们应用合并。