sql - CTE 递归以获取具有空级别的层次结构级别
问题描述
我在 SQL Server 2012 中有下面的表结构
INSERT INTO tblLocations (Relation, ParentID, Name, Levelnumber, Code)
VALUES
('Parent', NULL, 'West',0,'X'),
('Child', 1, 'WA',1,'X'),
('Grandchild', 2, 'Seattle',2,'X'),
('Grandchild', 2, 'Seattle2',2,'X'),
('GreatGrandchild', 3, 'aa',3,'X'),
('GreatGrandchild', 3, 'bb',3,'X'),
('Parent', NULL, 'MidWest',0,'Y'),
('Child', 7, 'IL',1,'Y'),
('Grandchild', 8, 'Chicago',2,'Y'),
('Grandchild',8, 'Chicago1',2,'Y'),
('GreatGrandchild', 9, 'cc',3,'Y'),
('GreatGrandchild', 9, 'dd',3,'Y'),
('Parent', NULL, 'South',0,'Z'),
('Child', 13, 'TX',1,'Z'),
('GreatGrandchild', 14, 'ff',3,'Z'),
('GreatGrandchild', 14, 'ff',3,'Z'),
('Parent', NULL, 'North',0,'A'),
('Grandchild',17, 'Chicago1',2,'A'),
('GreatGrandchild', 18, 'ff',3,'A'),
('GreatGrandchild', 18, 'ff',3,'A');
正如我们所见,并非所有节点都存在某些级别。我们的要求是获得所有节点的所有级别。
例如,对于代码 X
Parent -> Child -> GrandChild --> GreatGrandchild
层次结构在那里..但是对于代码A,我们有
Parent -> GrandChild -> GreatGrandChild
同样对于代码 Z:
Parent -> Child -> GreatGrandChild
我们的要求是,如果没有一个级别,则应为缺少的级别填充后续级别(由级别编号标识)。我们只有4个级别..
我们总是需要
Parent -> Child (if child is not there search down (Grandchild / GreatGrandchild) until data is there and populate as Child)
-> GrandChild - > GreatGrandChild
这是我们得到的CTE,
WITH Hierarchy AS
(
-- initialization
SELECT Relation, ParentID, Name, Levelnumber, Code
FROM tblLocations
WHERE LevelNumber = 0
UNION ALL
-- recursive execution
SELECT S.Relation, S.ParentID,S.Name,S.Levelnumber, S.Code
FROM tblLocations S
INNER JOIN tblLocations T ON T.Id = S.ParentId
)
SELECT *
FROM Hierarchy
WHERE Code = 'X' ;
我们需要它在视图中,所以没有 T-SQL。
请指导
解决方案
您的递归查询存在问题,因为它不是递归的。根据定义,递归查询是自引用的。您编写查询的方式,应该定义递归的部分只是表到自身的正常连接。
也就是说,一切都没有丢失。这是我想出的:
WITH Hierarchy AS
(
--initialization
SELECT ID,
Relation,
ParentID, [Name],
Levelnumber,
Code,
1 AS [__level__],
cast(concat('/', ID, '/') as varchar(max)) as h
FROM tblLocations
WHERE LevelNumber = 0
UNION ALL
--recursive execution
SELECT child.ID,
child.Relation,
child.ParentID,
child.Name,
child.Levelnumber,
child.Code,
parent.[__level__] + 1,
cast(concat(parent.h, child.ID, '/') as varchar(max)) as h
FROM tblLocations child
INNER JOIN Hierarchy AS parent
ON parent.Id = child.ParentId
)
SELECT *,
choose(
Hierarchy.[__level__],
'Parent',
'Child',
'GrandChild',
'GreatGrandchild'
) as [DerivedRelation]
FROM Hierarchy
WHERE Code = 'A'
order by h;
实际的递归查询是相当标准的层次结构遍历的东西。为了满足您的要求,我正在计算自己在层次结构中所处位置的概念,以便我可以使用它来确定您想要显示为关系的内容。你没有说你使用的是什么版本的 SQL,所以你可能没有concat()
和choose()
. 不过没关系;它们只是围绕string + string
和case
语句的语法糖。
我在这里要注意的另一件事是h
专栏。我已经编写了相当多的分层查询,对于它们的实际运行时执行,我更喜欢 hierarchyid。您在数据维护方面付出了一些代价,但是使用它们进行查询是相当高效的(因为您可以索引层次结构并说出类似的内容where h.IsDescendentOf(some_other_hierarchyID)
。所有这一切都是说该h
列可以直接转换为层次结构 ID 应该你想去那个方向。
推荐阅读
- autohotkey - 如何在不关闭脚本的情况下停止正在运行的 AHK 脚本?
- visual-studio-code - 如何在 VSCode 的 emmet 中转义大括号({ })
- python - 使用justpy构建Web应用程序,程序显示没有输出
- excel - 索引行和列意外结果
- javascript - javascript动画SVG在Wordpress中不起作用
- angular - 如何在角度路由模块中设置动态数据
- postgresql - SqlAlchemy:联合的 groupby 错误:SELECT 构造以包含在 UNION 或其他预期的集合构造中
- firebase - 从自托管服务器访问 Firestore
- javascript - 当类是被测试函数的参数而不是模块时,如何在 Jest 中测试使用了类方法?
- javascript - Material UI TextField Outline 在边框上溢出