TSQL递归CTE顺序
TSQL recursive CTE order
我无法弄清楚如何使用递归 CTE 对结果进行递归排序。这就是我的意思(这是一个简化的数据集):
我有这个作为输入:
declare @sections table (id int, parent int);
insert into @sections values (1, 1);
insert into @sections values (2, 2);
insert into @sections values (3, 2);
insert into @sections values (4, 2);
insert into @sections values (5, 4);
insert into @sections values (6, 1);
insert into @sections values (7, 6);
insert into @sections values (8, 6);
insert into @sections values (9, 6);
insert into @sections values (10, 9);
-- hierarchical view
--1
-- 6
-- 7
-- 8
-- 10
-- 9
--2
-- 3
-- 4
-- 5
我想要这个作为输出
编辑:行的顺序是这里的重要部分
-- id parent depth
-- 1 1 0
-- 6 1 1
-- 7 6 2
-- 8 6 2
-- 10 8 3
-- 9 6 2
-- 2 2 0
这是我能做的最好的了:
with section_cte as
(
select id, parent, 0 'depth' from @sections where id = parent
union all
select cte.id, cte.parent, depth + 1
from @sections s join section_cte cte on s.parent = cte.id where s.id <> s.parent
)
select *from section_cte
任何人都可以帮我调整这个查询以获得我需要的吗?
谢谢!
您错过了需要从 cte 识别深度的部分
WITH CTE AS (
SELECT
id
, parent
, 0 AS depth
FROM
@sections
WHERE
id=parent
UNION ALL
SELECT
s.id
, s.parent
, c.depth + 1
FROM
@sections s
JOIN CTE c ON s.parent=c.id AND s.id <> s.parent
)
SELECT *
FROM CTE;
在递归构建的时候,加个sequence是小事。在下面的示例中,顺序由标题的字母顺序驱动,但您可以使用任何其他可用的 key/sequence.
Declare @Table table (ID int,Pt int,Title varchar(50))
Insert into @Table values (0,null,'Tags'),(1,0,'Transportation'),(2,1,'Boats'),(3,1,'Cars'),(4,1,'Planes'),(5,1,'Trains'),(6,0,'Technology'),(7,6,'FTP'),(8,6,'HTTP'),(9,0,'Finance'),(10,9,'FTP'),(11,9,'401K'),(12,2,'Sail'),(13,2,'Powered'),(14,6,'Internet'),(15,6,'Database'),(16,15,'SQL Server'),(17,15,'MySQL'),(18,15,'MS Access')
Declare @Top int = null --<< Sets top of Hier Try 9
Declare @Nest varchar(25) =' ' --<< Optional: Added for readability
;with cteHB (Seq,ID,Pt,Lvl,Title) as (
Select Seq = cast(1000+Row_Number() over (Order by Title) as varchar(500))
,ID
,Pt
,Lvl=1
,Title
From @Table
Where IsNull(@Top,-1) = case when @Top is null then isnull(Pt,-1) else ID end
Union All
Select Seq = cast(concat(cteHB.Seq,'.',1000+Row_Number() over (Order by cteCD.Title)) as varchar(500))
,cteCD.ID
,cteCD.Pt,cteHB.Lvl+1
,cteCD.Title
From @Table cteCD
Join cteHB on cteCD.Pt = cteHB.ID)
,cteR1 as (Select Seq,ID,R1=Row_Number() over (Order By Seq) From cteHB)
,cteR2 as (Select A.Seq,A.ID,R2=Max(B.R1) From cteR1 A Join cteR1 B on (B.Seq like A.Seq+'%') Group By A.Seq,A.ID )
Select Hier='HierName'
,B.R1
,C.R2
,A.ID
,A.Pt
,A.Lvl
,Title = Replicate(@Nest,A.Lvl) + A.Title
--,A.Seq --<< Normally Excluded, but you can see how the sequence is built
From cteHB A
Join cteR1 B on A.ID=B.ID
Join cteR2 C on A.ID=C.ID
Order By A.Seq --<< Use R1 if Range Keys are used
Returns
Hier R1 R2 ID Pt Lvl Title
HierName 1 19 0 NULL 1 Tags
HierName 2 4 9 0 2 Finance
HierName 3 3 11 9 3 401K
HierName 4 4 10 9 3 FTP
HierName 5 12 6 0 2 Technology
HierName 6 9 15 6 3 Database
HierName 7 7 18 15 4 MS Access
HierName 8 8 17 15 4 MySQL
HierName 9 9 16 15 4 SQL Server
HierName 10 10 7 6 3 FTP
HierName 11 11 8 6 3 HTTP
HierName 12 12 14 6 3 Internet
HierName 13 19 1 0 2 Transportation
HierName 14 16 2 1 3 Boats
HierName 15 15 13 2 4 Powered
HierName 16 16 12 2 4 Sail
HierName 17 17 3 1 3 Cars
HierName 18 18 4 1 3 Planes
HierName 19 19 5 1 3 Trains
现在,您可能已经注意到 R1 和 R2。这些是我的范围键,通常用于在没有递归的情况下聚合数据。如果您不需要或不想要这些,只需删除 cteR1 和 cteR2(以及最终 SELECT 中的相应引用)。
EDIT
您还可以选择层次结构的一部分(即技术及其 children)。
您需要的技巧是创建一个符合您的业务规则的排序字符串。像这样。
WITH CTE AS (
SELECT
id, parent, 0 AS depth
--For MS SQL Server 2012+
,cast(format(id,'0000') as varchar(max)) sort
--For previous versions
,cast(stuff('0000',5-len(cast(id as varchar)),len(cast(id as varchar)),id) as varchar(max)) sort1
FROM @sections
WHERE id=parent
UNION ALL
SELECT s.id, s.parent, c.depth + 1
,sort + cast(format(s.id,'0000') as varchar(max)) sort
,sort + cast(stuff('0000',5-len(cast(s.id as varchar)),len(cast(s.id as varchar)),s.id) as varchar(max)) sort1
FROM @sections s
inner join CTE c ON s.parent=c.id AND s.id <> s.parent
)
SELECT *
FROM CTE
order by sort --or by sort1 depending on version
我无法弄清楚如何使用递归 CTE 对结果进行递归排序。这就是我的意思(这是一个简化的数据集):
我有这个作为输入:
declare @sections table (id int, parent int);
insert into @sections values (1, 1);
insert into @sections values (2, 2);
insert into @sections values (3, 2);
insert into @sections values (4, 2);
insert into @sections values (5, 4);
insert into @sections values (6, 1);
insert into @sections values (7, 6);
insert into @sections values (8, 6);
insert into @sections values (9, 6);
insert into @sections values (10, 9);
-- hierarchical view
--1
-- 6
-- 7
-- 8
-- 10
-- 9
--2
-- 3
-- 4
-- 5
我想要这个作为输出 编辑:行的顺序是这里的重要部分
-- id parent depth
-- 1 1 0
-- 6 1 1
-- 7 6 2
-- 8 6 2
-- 10 8 3
-- 9 6 2
-- 2 2 0
这是我能做的最好的了:
with section_cte as
(
select id, parent, 0 'depth' from @sections where id = parent
union all
select cte.id, cte.parent, depth + 1
from @sections s join section_cte cte on s.parent = cte.id where s.id <> s.parent
)
select *from section_cte
任何人都可以帮我调整这个查询以获得我需要的吗?
谢谢!
您错过了需要从 cte 识别深度的部分
WITH CTE AS (
SELECT
id
, parent
, 0 AS depth
FROM
@sections
WHERE
id=parent
UNION ALL
SELECT
s.id
, s.parent
, c.depth + 1
FROM
@sections s
JOIN CTE c ON s.parent=c.id AND s.id <> s.parent
)
SELECT *
FROM CTE;
在递归构建的时候,加个sequence是小事。在下面的示例中,顺序由标题的字母顺序驱动,但您可以使用任何其他可用的 key/sequence.
Declare @Table table (ID int,Pt int,Title varchar(50))
Insert into @Table values (0,null,'Tags'),(1,0,'Transportation'),(2,1,'Boats'),(3,1,'Cars'),(4,1,'Planes'),(5,1,'Trains'),(6,0,'Technology'),(7,6,'FTP'),(8,6,'HTTP'),(9,0,'Finance'),(10,9,'FTP'),(11,9,'401K'),(12,2,'Sail'),(13,2,'Powered'),(14,6,'Internet'),(15,6,'Database'),(16,15,'SQL Server'),(17,15,'MySQL'),(18,15,'MS Access')
Declare @Top int = null --<< Sets top of Hier Try 9
Declare @Nest varchar(25) =' ' --<< Optional: Added for readability
;with cteHB (Seq,ID,Pt,Lvl,Title) as (
Select Seq = cast(1000+Row_Number() over (Order by Title) as varchar(500))
,ID
,Pt
,Lvl=1
,Title
From @Table
Where IsNull(@Top,-1) = case when @Top is null then isnull(Pt,-1) else ID end
Union All
Select Seq = cast(concat(cteHB.Seq,'.',1000+Row_Number() over (Order by cteCD.Title)) as varchar(500))
,cteCD.ID
,cteCD.Pt,cteHB.Lvl+1
,cteCD.Title
From @Table cteCD
Join cteHB on cteCD.Pt = cteHB.ID)
,cteR1 as (Select Seq,ID,R1=Row_Number() over (Order By Seq) From cteHB)
,cteR2 as (Select A.Seq,A.ID,R2=Max(B.R1) From cteR1 A Join cteR1 B on (B.Seq like A.Seq+'%') Group By A.Seq,A.ID )
Select Hier='HierName'
,B.R1
,C.R2
,A.ID
,A.Pt
,A.Lvl
,Title = Replicate(@Nest,A.Lvl) + A.Title
--,A.Seq --<< Normally Excluded, but you can see how the sequence is built
From cteHB A
Join cteR1 B on A.ID=B.ID
Join cteR2 C on A.ID=C.ID
Order By A.Seq --<< Use R1 if Range Keys are used
Returns
Hier R1 R2 ID Pt Lvl Title
HierName 1 19 0 NULL 1 Tags
HierName 2 4 9 0 2 Finance
HierName 3 3 11 9 3 401K
HierName 4 4 10 9 3 FTP
HierName 5 12 6 0 2 Technology
HierName 6 9 15 6 3 Database
HierName 7 7 18 15 4 MS Access
HierName 8 8 17 15 4 MySQL
HierName 9 9 16 15 4 SQL Server
HierName 10 10 7 6 3 FTP
HierName 11 11 8 6 3 HTTP
HierName 12 12 14 6 3 Internet
HierName 13 19 1 0 2 Transportation
HierName 14 16 2 1 3 Boats
HierName 15 15 13 2 4 Powered
HierName 16 16 12 2 4 Sail
HierName 17 17 3 1 3 Cars
HierName 18 18 4 1 3 Planes
HierName 19 19 5 1 3 Trains
现在,您可能已经注意到 R1 和 R2。这些是我的范围键,通常用于在没有递归的情况下聚合数据。如果您不需要或不想要这些,只需删除 cteR1 和 cteR2(以及最终 SELECT 中的相应引用)。
EDIT
您还可以选择层次结构的一部分(即技术及其 children)。
您需要的技巧是创建一个符合您的业务规则的排序字符串。像这样。
WITH CTE AS (
SELECT
id, parent, 0 AS depth
--For MS SQL Server 2012+
,cast(format(id,'0000') as varchar(max)) sort
--For previous versions
,cast(stuff('0000',5-len(cast(id as varchar)),len(cast(id as varchar)),id) as varchar(max)) sort1
FROM @sections
WHERE id=parent
UNION ALL
SELECT s.id, s.parent, c.depth + 1
,sort + cast(format(s.id,'0000') as varchar(max)) sort
,sort + cast(stuff('0000',5-len(cast(s.id as varchar)),len(cast(s.id as varchar)),s.id) as varchar(max)) sort1
FROM @sections s
inner join CTE c ON s.parent=c.id AND s.id <> s.parent
)
SELECT *
FROM CTE
order by sort --or by sort1 depending on version