作者热门文章
- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
给定一个非常简单的表格,例如:
-- SQLite3
CREATE TABLE tst (
id INTEGER PRIMARY KEY AUTOINCREMENT,
parent_id INTEGER CHECK (parent_id <> id),
tag STRING NOT NULL,
FOREIGN KEY (parent_id) REFERENCES tst(id)
)
WITH RECURSIVE
(公共(public)表表达式)从任何节点向上到该树的“根”,或者从一个节点向下遍历到它的所有子节点(沿着所有分支)。以下是似乎适用于这两种情况的查询(分别):
WITH RECURSIVE t(id, parent_id, tag) AS (
SELECT id, parent_id, tag FROM tst WHERE id=:mynode
UNION ALL
SELECT t2.id, t2.parent_id, t2.tag FROM tst AS t2
JOIN t ON t.parent_id = t2.id
) SELECT * FROM t
WITH RECURSIVE t(id, parent_id, tag) AS (
SELECT id, parent_id, tag FROM tst WHERE id=?
UNION ALL
SELECT t2.id, t2.parent_id, t2.tag FROM tst AS t2
JOIN t ON t.id = t2.parent_id
) SELECT * FROM t
t.parent_id
和
t2.id
从第一个示例反转到另一个示例)。
parent_id IS NULL
所在的行然后对其执行第二个查询。但我认为必须有一个更优雅的解决方案。
最佳答案
我发现我之前的 RCTE 查询有效,但我的应用程序有两个主要缺陷。
ORDER BY
子句完全偏离了基础......所以即使我根据嵌套深度缩进每一行,生成的“大纲摘要”也是完全错误的。 WITH RECURSIVE tree (id, parent_id, tag, depth, path) AS (
SELECT id, parent_id, tag, 1 AS depth, '' AS path FROM tst WHERE id = (
WITH RECURSIVE t3 (id, parent_id) AS (
SELECT id, parent_id FROM tst WHERE id = :mynode
UNION ALL
SELECT t2.id, t2.parent_id FROM tst AS t2
JOIN t3 ON t3.parent_id=t2.id
) SELECT id FROM t3 WHERE parent_id IS NULL
) UNION ALL
SELECT t2.id, t2.parent_id, t2.tag, tree.depth+1,
path || '/' || CAST(t2.id AS VARCHAR) FROM tst AS t2
JOIN tree ON tree.id = t2.parent_id
) SELECT * FROM tree ORDER by path;
depth
和
path
“树”(CTE 虚拟)表的列,为我的第一个
SELECT
中的那些(虚拟)列提供初始值(使用
1 AS depth, '' AS path
(这对我来说是一个新技巧),然后在每一步通过递归修改它们
tree.depth+1, path || '/' || CAST(t2.id AS VARCHAR)
;然后,最后我可以将
path
用于我的
ORDER BY
并使用深度在我的应用程序中为每一行添加适当的缩进级别。
#!python
for each in db.execute("SELECT id FROM tst WHERE parent_id IS NULL").fetchall():
for row in db.execute(qry, each):
print("%s\t%s%s" % (row[0], ' ' * row[3], row[2]))
qry
是我上面描述的查询(实际上已调整为仅获取感兴趣的列,但此示例甚至适用于
*
那里)。在实践中,我可能会使用 LIMIT 和 OFFSET 对这些结果进行分页(正如我已经对不支持任何消息线程的表中的结果的平面列表所做的那样)。
CHECK
我放置表模式只是为了防止最简单的循环树形式。好像是
parent_id INTEGER CHECK (parent_id IS NULL or parent_id < id)
应该工作得更好。 (每条 parent_id -> id 链接链都必须单调递减......所以不可能有循环。
FOREIGN KEY
已经为
INSERT
语句强制执行该属性......但此检查强制执行也适用于
UPDATE
。 (技术上我想我应该在我的实际应用程序中使用“日期”字段,但我希望代理键就足够了)。
关于sql - CTE WITH RECURSIVE Up and back?如何从任何节点获取整棵树?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28824123/
我是一名优秀的程序员,十分优秀!