Sql server 分层数据的动态T-SQL查询
我正在尝试执行一个动态查询,以遍历child-parents表,并且我已经能够遍历顶级和第二级分层查询: 数据: 列Sql server 分层数据的动态T-SQL查询,sql-server,tsql,dynamic-sql,hierarchical-data,recursive-query,Sql Server,Tsql,Dynamic Sql,Hierarchical Data,Recursive Query,我正在尝试执行一个动态查询,以遍历child-parents表,并且我已经能够遍历顶级和第二级分层查询: 数据: 列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
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);
我怎样才能把这个问题扩展到dynamical我要检查所有的孩子?这是所需的输出:
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
以下是我试图实现的视觉解释:
我根本看不到动态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
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 |空| 26 | 1 | Z
如果路径可能有100多个节点,那么您需要在查询末尾添加
选项(maxrecursion 0)
,否则您将达到SQL Server默认允许的最大递归级别。您可以通过搜索类似或更早的递归查询上的材料来查找所需的材料
为了创建递归查询,您需要创建一个CTE
,其中第一个表是您的锚点,就像第一个级别中有列Parent
是NULL
一样。在同一CTE
中,您不断向该级别添加1。请在中找到答案
看起来和其他同行用很棒的演示发布的答案一样(我想到了…)。然而,下面的示例和示例可能有助于对递归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
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!
以递归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
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!
您不需要动态SQL来计算分层查询中的级别。根查询可以返回
1
作为级别,递归调用可以增加级别。我很确定文档示例显示了这一点,可以详细说明您的专栏j?它代表什么?您应该如何计算它?@JoPapou13变量j背后的思想是获取层次结构中的总列数,从顶层父级(j=5)开始计算while条件和union选择
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!