car*_*987 0 sql sql-server recursion recursive-query common-table-expression
我需要获取分层表的根节点(具有 PARENT_ID = NULL):
ID | PARENT_ID
60 NULL
21 60
11 NULL
23 11
24 21
25 23
14 24
13 25
Run Code Online (Sandbox Code Playgroud)
我想要这个结果:
ID | PARENT_ID | ROOT_ID |
-------------------------
1 NULL NULL
2 1 1
3 1 1
4 2 1
5 4 1
6 NULL NULL
7 6 6
8 7 6
Run Code Online (Sandbox Code Playgroud)
CTE是个好方法吗?我怎样才能创建它?
显然我可以有更多的一个根节点。我必须获取每个节点的根节点。
这就是我所做的:
;WITH RCTE AS
(
SELECT ID, PARENT_ID, ID as ROOT_ID
FROM TABLE r1
WHERE NOT EXISTS (SELECT * FROM TABLE r2 WHERE r2.ID = r1.PARENT_ID)
UNION ALL
SELECT rh.ID, rh.PARENT_ID,
CASE
WHEN rc.ROOT_ID = rh.ID then NULL
ELSE ROOT_ID
END
FROM dbo.TABLE rh
INNER JOIN RCTE rc ON rc.ID = rh.PARENT_ID
)
select distinct ID, PARENT_ID,
CASE WHEN ROOT_ID = ID THEN NULL
else ROOT_ID
end ROOT_ID
from RCTE
Run Code Online (Sandbox Code Playgroud)
但这是结果:
ID | PARENT_ID | ROOT_ID |
-------------------------
11 NULL NULL
60 NULL NULL
13 25 11
23 11 11
25 23 11
13 25 60
14 24 60
21 60 60
23 11 60
24 21 60
25 23 60
Run Code Online (Sandbox Code Playgroud)
但正如你所看到的,我有一些重复的内容:
ID | PARENT_ID | ROOT_ID |
-------------------------
13 25 60
23 11 60
25 23 60
Run Code Online (Sandbox Code Playgroud)
提前致谢!
像下面这样的东西应该可以满足您的需要。
WITH recCTE AS
(
SELECT ID,
Parent_ID AS original_Parent_ID,
Parent_ID as next_parent_id,
NULL as ROOT_ID,
CASE WHEN Parent_ID IS NULL THEN 1 END AS is_root
FROM yourtable
UNION ALL
SELECT
reccte.id,
reccte.original_Parent_ID,
yourtable.Parent_ID,
CASE WHEN yourtable.Parent_ID IS NULL THEN reccte.next_parent_id ELSE reccte.ROOT_ID END,
NULL
FROM
recCTE
INNER JOIN yourtable ON reccte.next_parent_id = yourtable.ID
)
SELECT ID, Original_Parent_ID as Parent_ID, ROOT_ID
FROM reccte
WHERE ROOT_ID IS NOT NULL OR is_root = 1
ORDER BY ID;
Run Code Online (Sandbox Code Playgroud)
在递归种子(第一个 SELECT)中,我们获取所有记录并标记哪个记录已经是根。
然后,在递归项(第二个 SELECT)中,我们查找父记录以获取原始记录。如果它的父级为 NULL,则我们填充该ROOT_ID列。
最后,我们从递归 CTE 中选择填充了 ROOT_ID 的记录或已经是根记录的记录。
CREATE TABLE yourtable (ID int, Parent_ID int);
INSERT INTO yourtable VALUES
(1, NULL),
(2, 1),
(3, 1),
(4, 2),
(5, 4),
(6, NULL),
(7, 6);
Run Code Online (Sandbox Code Playgroud)
WITH recCTE AS
(
SELECT ID,
Parent_ID AS original_Parent_ID,
Parent_ID as next_parent_id,
NULL as ROOT_ID,
CASE WHEN Parent_ID IS NULL THEN 1 END AS is_root
FROM yourtable
UNION ALL
SELECT
reccte.id,
reccte.original_Parent_ID,
yourtable.Parent_ID,
CASE WHEN yourtable.Parent_ID IS NULL THEN reccte.next_parent_id ELSE reccte.ROOT_ID END,
NULL
FROM
recCTE
INNER JOIN yourtable ON reccte.next_parent_id = yourtable.ID
)
SELECT ID, Original_Parent_ID as Parent_ID, ROOT_ID
FROM reccte
WHERE ROOT_ID IS NOT NULL OR is_root = 1
ORDER BY ID;
Run Code Online (Sandbox Code Playgroud)
+----+-----------+---------+
| ID | Parent_ID | ROOT_ID |
+----+-----------+---------+
| 1 | NULL | NULL |
| 2 | 1 | 1 |
| 3 | 1 | 1 |
| 4 | 2 | 1 |
| 5 | 4 | 1 |
| 6 | NULL | NULL |
| 7 | 6 | 6 |
+----+-----------+---------+
Run Code Online (Sandbox Code Playgroud)