我如何从间隔的内部文本构建带有 CTE 的嵌套树?
How can I build a nested tree with CTE from a spaced inner text?
给定以下 table 数据(从逗号分隔的组件列表导入数据)
[SQL CTE]
;WITH COMPONENTS(ID, TEXT, CHILD) AS
(
SELECT
ID,TEXT, (CASE WHEN PATINDEX(' %',TEXT)=1 THEN 1 ELSE 0 END)
FROM tblComponents
)
SELECT * FROM COMPONENTS
[TABLE DATA]
ID | TEXT | ISCHILD
------------------------------------------------
1 | PARENT1 | 0
2 | PARENT2 | 0
3 | CHILD1 | 1
4 | CHILD2 | 1
数据的间距标识上述CHILD1、CHILD2都是PARENT2的children。因为它们的开头有空格并且它们的顺序假定它们是 ID 2 的 children。
这可能吗?我已经 运行 查询 PATINDEX(' %',TEXT)=1
给我 ISCHILD。
注意:假设只有Parent->ManyChildren(不管TEXT有多少空格),没有grandchildren;我只对最初的关系感兴趣
[ORIGINAL DATA]
ID,COMPONENT,
44,"COMPONENT1 contains:",
45," CHILD1 ",
46," CHILD2 ",
47," CHILD3 ",
Expected/Needed 输出:
ID | TEXT | PARENT_ID
------------------------------------------------
1 | PARENT1 | 0
2 | PARENT2 | 0
3 | CHILD1 | 2
4 | CHILD2 | 2
您要 运行 遇到的一个大问题是,您正在按照 table 中记录的顺序对有关数据的信息进行编码。我可以向你保证,这只会导致死亡和毁灭。
值得庆幸的是,您确实有一个 "ID" 似乎可以在将记录写入文件系统的顺序之外维护数据的顺序,因此这是朝着正确方向迈出的一步。此外,您通过查找前导空格识别了 children。所以你在正确的轨道上。
下一步是确定Parent child人属于哪个。你可以这样做:
SELECT
id,
text,
ischild,
(
SELECT TOP 1 id FROM Components WHERE isChild = 0 AND children.id > Components.id ORDER BY id ASC
) AS parent_id
FROM components as children
如果层次结构比一层更深,并且您可以确定 child 连接到 parent 的唯一方法是通过前面的间距,那么您可以获得更多创意:
SELECT
id,
text,
ischild,
(
SELECT TOP 1 id FROM Components
WHERE
children.id > Components.id AND
(len(Components.text) - len(replace(Components.text,' ',''))) < (len(children.text) - len(replace(children.text, ' ',''))) AND
Components.isChild = 0
ORDER BY id ASC
) AS parent_id
FROM components as children
对于最后一个,我们将遍历每条记录,然后寻找具有以下特征的最高 parent id:
- 一个 ID 小于我们正在查看的 child 记录
- 前导空格少于我们正在查看的 child 记录
此语句的记录集现在将具有 child 的 ID 和 parent 的 ID。如果 parent 的 id 是 NULL 那么我们就知道我们处于层次结构的根节点。
从这里您可以构建一个递归视图来查看层次结构路径、节点深度以及您想要从层次结构中挤出的任何其他内容:
WITH recursiveCTE
AS
(
SELECT
id,
text,
parent_id,
CAST(NULL as VARCHAR(500)) as path
0 as depth
FROM new_components_table
WHERE parent_id IS NULL
UNION ALL
SELECT
nct.id,
nct.text,
nct.parent_id,
cte.path + '>' + nct.text as path,
cte.depth + 1 as depth
FROM
recursiveCTE cte
INNER JOIN new_components_table nct ON
cte.id = nct.parent_id
)
SELECT id,text,parent_id, path, depth FROM recursiveCTE
给定以下 table 数据(从逗号分隔的组件列表导入数据)
[SQL CTE]
;WITH COMPONENTS(ID, TEXT, CHILD) AS
(
SELECT
ID,TEXT, (CASE WHEN PATINDEX(' %',TEXT)=1 THEN 1 ELSE 0 END)
FROM tblComponents
)
SELECT * FROM COMPONENTS
[TABLE DATA]
ID | TEXT | ISCHILD
------------------------------------------------
1 | PARENT1 | 0
2 | PARENT2 | 0
3 | CHILD1 | 1
4 | CHILD2 | 1
数据的间距标识上述CHILD1、CHILD2都是PARENT2的children。因为它们的开头有空格并且它们的顺序假定它们是 ID 2 的 children。
这可能吗?我已经 运行 查询 PATINDEX(' %',TEXT)=1
给我 ISCHILD。
注意:假设只有Parent->ManyChildren(不管TEXT有多少空格),没有grandchildren;我只对最初的关系感兴趣
[ORIGINAL DATA]
ID,COMPONENT,
44,"COMPONENT1 contains:",
45," CHILD1 ",
46," CHILD2 ",
47," CHILD3 ",
Expected/Needed 输出:
ID | TEXT | PARENT_ID
------------------------------------------------
1 | PARENT1 | 0
2 | PARENT2 | 0
3 | CHILD1 | 2
4 | CHILD2 | 2
您要 运行 遇到的一个大问题是,您正在按照 table 中记录的顺序对有关数据的信息进行编码。我可以向你保证,这只会导致死亡和毁灭。
值得庆幸的是,您确实有一个 "ID" 似乎可以在将记录写入文件系统的顺序之外维护数据的顺序,因此这是朝着正确方向迈出的一步。此外,您通过查找前导空格识别了 children。所以你在正确的轨道上。
下一步是确定Parent child人属于哪个。你可以这样做:
SELECT
id,
text,
ischild,
(
SELECT TOP 1 id FROM Components WHERE isChild = 0 AND children.id > Components.id ORDER BY id ASC
) AS parent_id
FROM components as children
如果层次结构比一层更深,并且您可以确定 child 连接到 parent 的唯一方法是通过前面的间距,那么您可以获得更多创意:
SELECT
id,
text,
ischild,
(
SELECT TOP 1 id FROM Components
WHERE
children.id > Components.id AND
(len(Components.text) - len(replace(Components.text,' ',''))) < (len(children.text) - len(replace(children.text, ' ',''))) AND
Components.isChild = 0
ORDER BY id ASC
) AS parent_id
FROM components as children
对于最后一个,我们将遍历每条记录,然后寻找具有以下特征的最高 parent id:
- 一个 ID 小于我们正在查看的 child 记录
- 前导空格少于我们正在查看的 child 记录
此语句的记录集现在将具有 child 的 ID 和 parent 的 ID。如果 parent 的 id 是 NULL 那么我们就知道我们处于层次结构的根节点。
从这里您可以构建一个递归视图来查看层次结构路径、节点深度以及您想要从层次结构中挤出的任何其他内容:
WITH recursiveCTE
AS
(
SELECT
id,
text,
parent_id,
CAST(NULL as VARCHAR(500)) as path
0 as depth
FROM new_components_table
WHERE parent_id IS NULL
UNION ALL
SELECT
nct.id,
nct.text,
nct.parent_id,
cte.path + '>' + nct.text as path,
cte.depth + 1 as depth
FROM
recursiveCTE cte
INNER JOIN new_components_table nct ON
cte.id = nct.parent_id
)
SELECT id,text,parent_id, path, depth FROM recursiveCTE