4

假设在 SQL 中实现了一个树结构,如下所示:

CREATE TABLE nodes (
    id INTEGER PRIMARY KEY,
    parent INTEGER -- references nodes(id)
);

尽管可以在这种表示中创建循环,但我们假设我们永远不会让这种情况发生。该表将仅存储根(父为空的记录)及其后代的集合。

目标是,给定表上一个节点的 id,找到它的所有后代节点。

如果A的父级是BA的父级是B的后代,则A是B的后代。注意递归定义。

以下是一些示例数据:

INSERT INTO nodes VALUES (1, NULL);
INSERT INTO nodes VALUES (2, 1);
INSERT INTO nodes VALUES (3, 2);
INSERT INTO nodes VALUES (4, 3);
INSERT INTO nodes VALUES (5, 3);
INSERT INTO nodes VALUES (6, 2);

这代表:

1
`-- 2
    |-- 3
    |   |-- 4
    |   `-- 5
    |
    `-- 6

1我们可以通过这样做来选择的(直接)孩子:

SELECT a.* FROM nodes AS a WHERE parent=1;

1我们可以通过这样做来选择子孙:

SELECT a.* FROM nodes AS a WHERE parent=1
UNION ALL
SELECT b.* FROM nodes AS a, nodes AS b WHERE a.parent=1 AND b.parent=a.id;

1我们可以通过这样做来选择孩子、孙子和曾孙:

SELECT a.* FROM nodes AS a WHERE parent=1
UNION ALL
SELECT b.* FROM nodes AS a, nodes AS b WHERE a.parent=1 AND b.parent=a.id
UNION ALL
SELECT c.* FROM nodes AS a, nodes AS b, nodes AS c WHERE a.parent=1 AND b.parent=a.id AND c.parent=b.id;

如何构造一个查询来获取节点的所有后代1而不是固定深度的后代?似乎我需要创建一个递归查询或其他东西。

我想知道使用 SQLite 是否可以进行这样的查询。但是,如果这种类型的查询需要 SQLite 中没有的功能,我很想知道它是否可以在其他 SQL 数据库中完成。

4

3 回答 3

9

一些数据库允许使用递归公用表表达式,但不允许使用 SQLite。

您可以考虑更改表定义。使用这样的表,很容易查询 1 的所有后代:

id (varchar)
--------------
001
001002
001002003
001002003004
001002003005
001002006

这允许您查询 1 的所有后代,例如:

SELECT * FROM YourTable WHERE id LIKE '001%'

这听起来有点古怪,但在实践中效果很好。

于 2010-04-30T04:21:03.130 回答
6

您设置模式的方式并不真正适合关系模型(正如您所发现的那样)。但是还有另一种方式,一开始可能不那么明显,但更灵活。它被称为“嵌套集合模型”,只是结构略有不同。

在 MySQL 中管理分层数据(查找“嵌套集模型”部分)展示了如何在 MySQL 中执行此操作,但它应该相当容易地转换为 SQLite。我不会在这里详细介绍,因为那篇文章实际上很长,但它应该给你所有你需要的东西。

于 2010-04-30T04:16:13.510 回答
1

Oracle 有一个可以用于此的 CONNECT BY 语法,但当然它是特定于 oracle 的。

于 2010-04-30T04:20:57.170 回答