1

我有一个用于存储层次结构的表,它引用自身。我需要一个确定父节点类型的 SQL 语句。下面我给出了我的表格的结构以及示例数据,以提供对我想要弄清楚的内容的最佳解释。

节点表

CREATE TABLE IF NOT EXISTS NODES(id INTEGER PRIMARY KEY AUTOINCREMENT, type TEXT NOT NULL, parent_id INTEGER REFERENCES NODES(id) ON DELETE CASCADE

注意:parent_id可以为 NULL 以引用 ROOT 节点。

样本数据

INSERT INTO NODES(type, parent_id) VALUES('GRP', NULL); -- id: 1, title: Hello, World!
INSERT INTO NODES(type, parent_id) VALUES('TXT', 1);    -- id: 2, title: Print
INSERT INTO NODES(type, parent_id) VALUES('RND', 1);    -- id: 3, title: Random Output
INSERT INTO NODES(type, parent_id) VALUES('TXT', 3);    -- id: 4, title: OUTPUT #1
INSERT INTO NODES(type, parent_id) VALUES('TXT', 3);    -- id: 5, title: OUTPUT #2
INSERT INTO NODES(type, parent_id) VALUES('TXT', 3);    -- id: 6, title: OUTPUT #3

每个节点都有标题,我在评论中列出了,但为了可用性我只是把它们放在评论中。我想要做的是有一个单一的 SQL 语句来返回所有内容,但 OUTPUT #* 使用父级的属性。

我的尝试

SELECT id
FROM NODES
WHERE parent_id NOT IN (SELECT id
                        FROM NODES
                        WHERE type = 'RND');

我的尝试在大多数情况下都有效,但由于 parent_id 可以为 NULL,我通过研究得知 aJOIN将是一个更好的解决方案。我只是不知道如何让 SELF JOIN 以我想要的方式工作。

4

2 回答 2

1

您的查询确实没有返回“Hello, World!” 节点,因为与NULL总是失败的比较。您可以通过添加以下特殊情况来修改此查询以包含没有父节点的节点:

SELECT id
FROM NODES
WHERE parent_id NOT IN (SELECT id
                        FROM NODES
                        WHERE type = 'RND')
   OR parent_id IS NULL

可以通过连接来做到这一点,但是

  1. 您不能使用普通(内部)联接,因为这与NULL值不匹配,您必须改用外部联接;和
  2. 您仍然需要为无父节点添加特殊情况,因为外连接将丢失父节点的所有值设置为NULL; 和
  3. 您现在有两个表,因此您必须使用别名,并为每个列名指定表:
SELECT child.id
FROM nodes AS child
LEFT JOIN nodes AS parent ON child.parent_id = parent.id
WHERE parent.type <> 'RND'
   OR parent.type IS NULL
于 2013-09-03T20:24:22.103 回答
1

此查询根据 parent_id 将表连接到自身,并显示来自节点及其父节点的所有字段。因为使用了左连接,所以结果将包括所有节点及其父节点,包括根节点。

因为同一个表在同一个查询中被引用了两次,所以必须使用别名来区分这两个表。语法“nodes as parent”创建别名“parent”。

SELECT nodes.*, parent.*
FROM nodes
LEFT JOIN nodes AS parent
ON nodes.parent_id = parent.id

要查找父类型不等于上述查询中的“RND”的节点,您需要将以下 where 子句添加到查询中。

WHERE parent.type != 'RND' OR parent.type IS NULL

我认为您在上述查询中缺少的重要一点是 NULL 值和比较运算符一起工作的方式。NULL 与大多数比较运算符和任何其他值的结果始终为假。这就是为什么在上面的 where 子句中需要第二个条件。“IS”关键字是一个特殊关键字,可用于检查空值。

于 2013-09-03T20:26:20.003 回答