![](/img/trans.png)
[英]SQLAlchemy: order_by(None) for joinedload subclause queries?
[英]Recursive CTE with subclause in SQLAlchemy
我正在尝试在 SQLAlchemy 中实现一个 CTE,它从父/子树中的给定节点返回一个根节点。
我能够按照递归 CTE 查询中的示例在 SQLAlchemy 中生成 CTE 递归。
但我不确定如何在其上附加附加条件。 即:
WITH ...
SELECT parent_id from parents
WHERE parent_id NOT IN (SELECT child_id FROM node_parent_relation );
我想这样做,以便我只返回根节点。
查询在 SQL 中工作。
WITH RECURSIVE parents( child_id, parent_id )
AS (
-- get leaf children
SELECT child_id, parent_id
FROM node_parent_relation
WHERE child_id = '4415b581-0a31-43e8-a69d-d74caeccacd2'
UNION ALL
-- get all parents
SELECT t.child_id, t.parent_id
FROM parents p
JOIN node_parent_relation t
ON p.parent_id = t.child_id
)
SELECT parent_id from parents
WHERE parent_id NOT IN (SELECT child_id FROM node_parent_relation );
但是我可以看到如何将这个附加子句添加到我的 SQLAlchemy 语句中。
我想这将涉及在某处添加这些语句。
sub_query = db.session.query(NodeParentRelation.child_id)
[...].filter([...].parent_id.in_(sub_query))
这是我的 SQLAlchemy 代码目前的样子:
parent = aliased(NodeParentRelation)
child = aliased(NodeParentRelation)
sub_query = db.session.query(NodeParentRelation.child_id)
top_query = db.session.query(NodeParentRelation.child_id,
NodeParentRelation.parent_id)\
.filter(NodeParentRelation.child_id == self.id)\
.cte(recursive=True)
bottom_query = db.session.query(child.child_id, child.parent_id)\
.join(parent, parent.parent_id == child.child_id)
query = top_query.union(bottom_query)
作为参考,这是当前正在从上述 SQLAlchemy 语句构建的 SQL 查询。
WITH RECURSIVE anon_1(child_id, parent_id) AS
(SELECT node_parent_relation.child_id AS child_id, node_parent_relation.parent_id AS parent_id
FROM node_parent_relation
WHERE node_parent_relation.child_id = %(child_id_1)s UNION SELECT node_parent_relation_1.child_id AS node_parent_relation_1_child_id, node_parent_relation_1.parent_id AS node_parent_relation_1_parent_id
FROM node_parent_relation AS node_parent_relation_1 JOIN node_parent_relation AS node_parent_relation_2 ON node_parent_relation_2.parent_id = node_parent_relation_1.child_id)
SELECT anon_1.child_id AS anon_1_child_id, anon_1.parent_id AS anon_1_parent_id
FROM anon_1
当前查询根本不引用递归步骤中的 CTE。 您需要 CTE 本身的别名来解决这个问题:
In [5]: top_query = db.session.query(NodeParentRelation.child_id,
...: NodeParentRelation.parent_id)\
...: .filter(NodeParentRelation.child_id == 1)\
...: .cte(recursive=True)
...:
In [6]: parents = db.aliased(top_query)
In [7]: t = db.aliased(NodeParentRelation)
In [11]: query = top_query.union_all(
...: db.session.query(t.child_id, t.parent_id).
...: join(parents, t.child_id == parents.c.parent_id))
其余的是非常标准的东西:
In [14]: db.session.query(query.c.parent_id).\
...: filter(query.c.parent_id.notin_(
...: db.session.query(NodeParentRelation.child_id)))
Out[14]: <sqlalchemy.orm.query.Query at 0x7f56bf55b668>
In [15]: print(_)
WITH RECURSIVE anon_1(child_id, parent_id) AS
(SELECT node_parent_relation.child_id AS child_id, node_parent_relation.parent_id AS parent_id
FROM node_parent_relation
WHERE node_parent_relation.child_id = ? UNION ALL SELECT node_parent_relation_1.child_id AS node_parent_relation_1_child_id, node_parent_relation_1.parent_id AS node_parent_relation_1_parent_id
FROM node_parent_relation AS node_parent_relation_1 JOIN anon_1 AS anon_2 ON node_parent_relation_1.child_id = anon_2.parent_id)
SELECT anon_1.parent_id AS anon_1_parent_id
FROM anon_1
WHERE anon_1.parent_id NOT IN (SELECT node_parent_relation.child_id AS node_parent_relation_child_id
FROM node_parent_relation)
虽然我个人更喜欢不存在:
In [25]: db.session.query(query.c.parent_id).\
...: filter(~db.session.query(NodeParentRelation).
...: filter(NodeParentRelation.child_id == query.c.parent_id).
...: exists())
...:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.