Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 分层数据的动态T-SQL查询_Sql Server_Tsql_Dynamic Sql_Hierarchical Data_Recursive Query - Fatal编程技术网

Sql server 分层数据的动态T-SQL查询

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

我正在尝试执行一个动态查询,以遍历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 @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!