sql - 在自我参照表中找到最顶层的父母
问题描述
给定多个 ID,每个 ID 都可能连接到同一张表中的其他条目,我想找到它们的顶级父级。即父 ID 为的那些行NULL
。因此,在每个红色单元下方,都会将层次结构连接到相应的绿色单元。
在一个非常相似的问题中借用这个答案,这是一个玩具模式。
DECLARE @t TABLE (ID INT, link INT)
INSERT INTO @t VALUES
(1, NULL),
(2, 1),
(3, 2),
(4, 3),
(5, 3),
(6, 2),
(7, 1),
(8, NULL),
(9, 8),
(10, 9),
(11, 9),
(12, 9),
(13, 12),
(14, 12),
(15, 8);
对于具有两个底层节点的示例,我将有一组 ID 6 和 13。然后我想要一个像 (6, 1) 和 (13, 8) 这样的结果集。为了构建每个链接,答案建议使用公共表表达式。
WITH cte AS (
SELECT ID, link
FROM @t
WHERE ID IN (6, 13)
UNION ALL
SELECT t.ID, t.link
FROM @t t
JOIN cte c ON t.ID = c.link
WHERE t.link IS NOT NULL
)
SELECT *
FROM cte
这产生了这个结果:
ID | link
----+------
6 | 2
13 | 12
12 | 9
9 | 8
2 | 1
但是,我不确定如何将其组合成每个起点的结果。对于一个 ID,我也许可以选择结果集的最后一行并获取链接 ID,但不能用于多个。请注意,自然可以有多个顶级父级(尽管分支只发生向下,因此给定节点只有一个父级),也可以选择中级条目作为起点。
而不是UNION ALL
我天真地尝试过JOIN
,但事实证明这样的 CTE 是不允许的。
以下是上面所有的红色节点:(3, 6, 11, 13, 15)
. 他们应该映射到(1, 1, 8, 8, 8)
.
解决方案
代码的2个问题:
- 你需要通过递归来追踪你的起始ID;
- 递归部分中的
where
条件实际上是在阻止您获得结果。
像这样:
WITH cte AS (
SELECT ID, link, ID as [StartID]
FROM @t
WHERE ID IN (6, 7)
UNION ALL
SELECT t.ID, t.link, c.StartID
FROM @t t
JOIN cte c ON t.ID = c.link
)
SELECT c.StartID, c.ID
FROM cte c
where c.link is null;
推荐阅读
- html - 如何在 bootsrap 5 中向导航栏添加文本颜色?
- react-native - 虽然我没有使用 useEffect 钩子
- android - 任务进入后台或进入前台时回调?
- php - 尝试将图像路径上传到数据库时出现此错误“从空值创建默认对象”
- python - etcd 响应在 Python 3.9 应用程序中不包含集群 ID
- sql - 对 SQL 进行排序时,如何添加额外的规则与上一行?
- python - 为什么我的代码不能对列表中负数的值求和?
- c++ - 如何在 Visual Studio 中对 C 项目进行单元测试和模拟
- javascript - Prestashop 分页上一个按钮的奇怪行为
- node.js - Node js 上的 azure 函数返回错误 mscorlib:执行函数时出现异常:Functions.users。mscorlib:发生一个或多个错误