【问题标题】:SQL get leaves of directed acyclic graphSQL获取有向无环图的叶子
【发布时间】:2019-05-16 01:03:41
【问题描述】:

我对 SQL 很陌生,并且有一个相当基本的问题。假设我正在处理以下表结构:

CREATE TABLE nodes (
  id INTEGER NOT NULL PRIMARY KEY,
  parent INTEGER REFERENCES nodes(id)
);

如果我们持有一个不变量,即节点的父节点不能等同于它的任何子节点,那么根据定义,我们的图中不会有任何循环。现在我们得到了一个不相交的有向无环图。

我的两个问题是:

  1. 如果我们无法更改数据库的结构:我必须编写什么select 语句才能有效地获取数据库中的所有叶子? IE。没有任何孩子的 id。
  2. 如果我们可以更改表的结构:我们可以更改或添加什么来使select 语句更高效?

具有五个节点的图的输出示例,其父节点 3->2、2->1 和 5->4 将输出 3 和 5,因为它们是唯一没有子节点的节点。

【问题讨论】:

  • 你用的是什么版本的 MySQL?
  • 假设 8.0 没问题
  • 这读起来很像家庭作业。

标签: sql graph-theory mysql-8.0


【解决方案1】:

您可以使用NOT EXISTS 和相关子查询来检查当前不是父节点的节点。对于叶子,不存在这样的记录。

SELECT *
       FROM nodes n1
       WHERE NOT EXISTS (SELECT *
                                FROM nodes n2
                                WHERE n2.parent = n1.id);

另一个选项是左连接连接节点的可能子节点。如果连接的“子方”的id 为空,则当前节点不存在子节点。

SELECT *
       FROM nodes n1
            LEFT JOIN nodes n2
                      ON n2.parent = n1.id
       WHERE n2.id IS NULL;

而且,除了非规范化之外,我认为表的结构没有太多需要改变的地方。不过,索引可能会有所帮助。一个应该在id 上(但由于主键约束已经是这种情况),一个在parent 上(但同样的索引已经存在,因为 MySQL 为外键元组创建索引)。

【讨论】:

    【解决方案2】:

    对于更复杂的图形查询,您可以使用公共表表达式 (CTE),在 SQL:99 中标准化并在 MySQL 8.0.1 (reference) 中得到支持

    但正如其他人指出的那样,对于您感兴趣的查询,一个简单的NOT EXISTS 子查询或等效的就足够了。另一个与已经发布的等效的方法是使用EXCEPT set 操作:

    SELECT id FROM nodes
    EXCEPT SELECT parent FROM nodes
    

    【讨论】:

    • 我很少看到有人使用 EXCEPT/MINUS。 +1
    【解决方案3】:

    我愿意:

    select *
    from nodes
    where id not in (select parent from nodes where parent is not null)
    

    【讨论】:

    • 这个选择给我留下了一个空的结果?
    • 已修复。 WHERE 谓词需要添加到子查询中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-12-11
    • 1970-01-01
    • 1970-01-01
    • 2015-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多