我正在尝试通过子表-Parents表进行动态查询,并且已经能够通过顶层和第二层层次查询:
数据:
create table temp
(
Pos int
,Child nvarchar(18)
,Parent nvarchar(18)
,Test int
);
insert into temp (Pos, Child, Parent, Test)
values
(1, 'A', NULL, 1),
(2, 'J', NULL, 10),
(3, 'P', NULL, 16),
(4, 'Y', NULL, 25),
(1, 'B', 'A', 2),
(2, 'E', 'A', 5),
(1, 'C', 'B', 3),
(2, 'D', 'B', 4),
(1, 'F', 'E', 6),
(2, 'G', 'E', 7),
(1, 'H', 'G', 8),
(2, 'I', 'G', 9),
(1, 'K', 'J', 11),
(2, 'L', 'J', 12),
(3, 'M', 'J', 13),
(1, 'N', 'M', 14),
(2, 'O', 'M', 15),
(5, 'Z', NULL, 26),
(1, 'Q', 'P', 17),
(2, 'S', 'P', 19),
(3, 'T', 'P', 20),
(4, 'X', 'P', 24),
(1, 'R', 'Q', 18),
(1, 'U', 'T', 21),
(2, 'V', 'T', 22),
(3, 'W', 'T', 23)
第Test
列仅在最后看数据是否正确排序
到目前为止,我的代码:
declare @sql nvarchar(max);
declare @tlp nvarchar(max); --top level parents
declare @i nvarchar(4);
declare @j nvarchar(4);
declare @l nvarchar(4); --level
set @tlp = ';with tlp as (
select ROW_NUMBER() over (order by Pos) as j, * from temp where Parent IS NULL
)';
set @i = 1;
set @j = (select COUNT(*) as j from temp where Parent IS NULL);
set @sql = @tlp;
while @i < @j
begin
set @l = 1;
set @sql += '
select ' + @l + ' as Level, * from tlp where j = ' + @i
set @l = @l + 1
set @sql += '
union all
select ' + @l + ' as Level, ROW_NUMBER() over (order by Pos), * from temp where Parent = (select Child from tlp where j = ' + @i + ')'
set @i = @i + 1
if @i < @j set @sql += '
union all'
end;
exec(@sql);
输出:
level j Pos Child Parent Test
1 1 1 A NULL 1
2 1 1 B A 2
2 2 2 E A 5
1 2 2 J NULL 10
2 1 1 K J 11
2 2 2 L J 12
2 3 3 M J 13
1 3 3 P NULL 16
2 1 1 Q P 17
2 2 2 S P 19
2 3 3 T P 20
2 4 4 X P 24
1 4 4 Y NULL 25
如何扩展查询以动态遍历所有子项?这是所需的输出:
Level j Pos Child Parent Test
1 1 1 A NULL 1
2 1 1 B A 2
3 1 1 C B 3
3 2 2 D B 4
2 2 2 E A 5
3 1 1 F E 6
3 2 2 G E 7
4 1 1 H G 8
4 2 2 I G 9
1 2 2 J NULL 10
2 1 1 K J 11
2 2 2 L J 12
2 3 3 M J 13
3 1 1 N M 14
3 2 2 O M 15
1 3 3 P NULL 16
2 1 1 Q P 17
3 1 1 R Q 18
2 2 2 S P 19
2 3 3 T P 20
3 1 1 U T 21
3 2 2 V T 22
3 3 3 W T 23
3 4 4 X P 24
1 4 4 Y NULL 25
1 5 5 Z NULL 26
这是我想要实现的视觉解释:
答案 0 :(得分:3)
我根本看不到动态SQL的。您具有要以深度优先的方式行走的分层数据。在SQL中,这通常是通过递归查询完成的。要管理行的顺序,您可以跟踪每个节点的路径。
考虑:
with cte as (
select t.*, 1 lvl, cast(child as nvarchar(max)) path
from temp t
where parent is null
union all
select t.*, c.lvl + 1, c.path + '/' + cast(t.child as nvarchar(max))
from cte c
inner join temp t on t.parent = c.child
)
select * from cte order by path
Pos | Child | Parent | Test | lvl | path --: | :---- | :----- | ---: | --: | :------ 1 | A | null | 1 | 1 | A 1 | B | A | 2 | 2 | A/B 1 | C | B | 3 | 3 | A/B/C 2 | D | B | 4 | 3 | A/B/D 2 | E | A | 5 | 2 | A/E 1 | F | E | 6 | 3 | A/E/F 2 | G | E | 7 | 3 | A/E/G 1 | H | G | 8 | 4 | A/E/G/H 2 | I | G | 9 | 4 | A/E/G/I 2 | J | null | 10 | 1 | J 1 | K | J | 11 | 2 | J/K 2 | L | J | 12 | 2 | J/L 3 | M | J | 13 | 2 | J/M 1 | N | M | 14 | 3 | J/M/N 2 | O | M | 15 | 3 | J/M/O 3 | P | null | 16 | 1 | P 1 | Q | P | 17 | 2 | P/Q 1 | R | Q | 18 | 3 | P/Q/R 2 | S | P | 19 | 2 | P/S 3 | T | P | 20 | 2 | P/T 1 | U | T | 21 | 3 | P/T/U 2 | V | T | 22 | 3 | P/T/V 3 | W | T | 23 | 3 | P/T/W 4 | X | P | 24 | 2 | P/X 4 | Y | null | 25 | 1 | Y 5 | Z | null | 26 | 1 | Z
如果路径可能包含100个以上的节点,则需要在查询末尾添加option(maxrecursion 0)
,否则将达到SQL Server默认情况下允许的最大递归级别。
答案 1 :(得分:2)
您可以通过在递归查询中搜索诸如articles或更早的answers之类的内容来找到要问的内容。
要创建递归查询,请创建一个CTE
,其中第一个表是您的锚点,就像第一级一样,其中有列Parent
是NULL
。在同一CTE
中,您将1继续添加到该级别。请在Fiddle
WITH MyCTE AS (
SELECT *, 1 AS Level
FROM temp
WHERE Parent IS NULL
UNION ALL
SELECT t.Pos, t.Child, t.Parent, t.Test, MyCTE.Level+1 AS Level
FROM temp AS t
INNER JOIN MyCTE
ON t.Parent = MyCTE.Child
WHERE t.Parent IS NOT NULL)
SELECT MyCTE.*, CASE WHEN Offsprings.Offspring IS NULL THEN 1 ELSE Offsprings.Offspring END AS Offspring
FROM MyCTE
LEFT JOIN (
SELECT Parent, COUNT(Parent) AS Offspring
FROM temp
GROUP BY Parent)Offsprings
ON MyCTE.Child = Offsprings.Parent
ORDER BY MyCTE.Child
答案 2 :(得分:0)
似乎是其他同行以出色演示发布的相同答案(我认为..)。但是,下面的示例和this post可能有助于简化和更好地了解递归CTE
DDL
create table temp
(
recid int identity (1,1)
,Pos_ID int
,Child_Pos nvarchar(50)
,Parent_Pos nvarchar(50)
);
insert into temp (Pos_ID, Child_Pos, Parent_Pos)
values
(1, 'Super Boss', NULL),
(2, 'Boss', 'Super Boss'),
(3, 'Sr. Mangaer 1', 'Boss'),
(3, 'Sr. Mangaer 2', 'Boss'),
(3, 'Sr. Mangaer 3', 'Boss'),
(4, 'Mangaer 1', 'Sr. Mangaer 1'),
(4, 'Mangaer 2', 'Sr. Mangaer 1'),
(4, 'Mangaer 3', 'Sr. Mangaer 2'),
(4, 'Mangaer 4', 'Sr. Mangaer 2'),
(4, 'Mangaer 5', 'Sr. Mangaer 3'),
(4, 'Mangaer 6', 'Sr. Mangaer 3'),
(5, 'Emp 01', 'Mangaer 1'),
(5, 'Emp 02', 'Mangaer 1'),
(5, 'Emp 03', 'Mangaer 2'),
(5, 'Emp 04', 'Mangaer 2'),
(5, 'Emp 05', 'Mangaer 3'),
(5, 'Emp 06', 'Mangaer 3'),
(5, 'Emp 07', 'Mangaer 4'),
(5, 'Emp 08', 'Mangaer 4'),
(5, 'Emp 09', 'Mangaer 5'),
(5, 'Emp 10', 'Mangaer 5'),
(5, 'Emp 11', 'Mangaer 6'),
(5, 'Emp 12', 'Mangaer 6')
go
递归CTE示例
with main as (
select Child_Pos, Parent_Pos,Pos_ID, 1 as Reculevel
from temp as t1
--where Parent_Pos is not null
UNION ALL
select t2.Child_Pos, t2.Parent_Pos, t2.Pos_ID, main.Reculevel + 1
from temp as t2
join main on t2.Parent_Pos = main.Child_Pos
)
select * from main
为您的示例遵循递归CTE
with main as (
select Pos, Child, Parent, Test, 1 as RecuLevel
from temp as t1
UNION ALL
select t2.Pos, t2.Child, t2.Parent, t2.Test, RecuLevel + 1
from temp as t2
join main on t2.Parent = main.Child
)
select * from main
--option (maxrecursion 0) -- be cautious enabling this!