Joh*_*tos 6 t-sql sql-server recursion common-table-expression sql-server-2012
我在SQL Server(2012)中有以下表:
MyTable:
Id __ParentId Priority
1 NULL NULL
2 1 100
3 1 300
4 1 200
5 4 100
6 4 200
7 6 100
8 5 100
9 5 200
10 9 100
11 5 50
Run Code Online (Sandbox Code Playgroud)
该__ParentId列引用标识知道任何一行的父,它可以深入到递归的许多级别(例如,标识8是一个孩子的5是一个孩子的4这是一个孩子1).
此外,还有一个优先级列,显示子项应出现在父项中的顺序(获取优先级的最低数字).
所以,我想得到的决赛桌是:
Id __ParentId Priority Order
1 NULL NULL 1
2 1 100 2
4 1 200 3
5 4 100 4
11 5 50 5
8 5 100 6
9 5 200 7
10 9 100 8
6 4 200 9
7 6 100 10
3 1 300 11
Run Code Online (Sandbox Code Playgroud)
为了解释一下,我们认为这2是一个孩子,1并且具有最高优先级,但没有孩子,所以我们就在那里,然后4是下一个优先孩子,接下来就是它,但后来我们分成了孩子和他们的孩子基于优先级和层次结构.
或者,通过树结构解释:
1
2
4
5
11
8
9
10
6
7
3
Run Code Online (Sandbox Code Playgroud)
我可以创建CTE,它将给我一个父母的孩子,但我无法找到一个好的方法来获得正确的顺序,所以甚至不能提供一个很好的SQL我一直在尝试.
Bog*_*ean 10
SQL2008 +:
尝试以下解决方案
DECLARE @TableA TABLE (
Id INT NOT NULL PRIMARY KEY,
__ParentId INT NULL,
[Priority] INT NULL
);
INSERT @TableA (Id, __ParentId, [Priority])
VALUES
(1 ,NULL,NULL),
(2 ,1 ,100 ),
(3 ,1 ,300 ),
(4 ,1 ,200 ),
(5 ,4 ,100 ),
(6 ,4 ,200 ),
(7 ,6 ,100 ),
(8 ,5 ,100 ),
(9 ,5 ,200 ),
(10,9 ,100 ),
(11,5 ,50 );
WITH CteRecursive
AS (
SELECT a.Id, a.__ParentId, a.[Priority], CONVERT(HIERARCHYID, '/' + LTRIM(a.Id) + '/') AS HID
FROM @TableA a
WHERE a.__ParentId IS NULL
UNION ALL
SELECT cld.Id, cld.__ParentId, cld.[Priority], CONVERT(HIERARCHYID, prt.HID.ToString() + LTRIM(cld.[Priority]) + '/') AS HID
FROM CteRecursive prt -- Parent
JOIN @TableA cld ON prt.Id = cld.__ParentId -- Child
WHERE cld.__ParentId IS NOT NULL
)
SELECT *, r.HID.ToString() AS HIDToString FROM CteRecursive r
ORDER BY r.HID ASC
Run Code Online (Sandbox Code Playgroud)
结果:
注意#1:此解决方案使用HIERARCHYID排序的一个属性:使用深度优先方法(这意味着父级,然后是所有子级)对HID值进行排序.
给定两个hierarchyid值a和b,小于b表示a在树的深度优先遍历中位于b之前.hierarchyid数据类型的索引按深度优先顺序排列,并且深度优先遍历中彼此靠近的节点彼此靠近存储.例如,记录的子项存储在该记录附近.有关更多信息,请参阅分层数据(SQL Server).
这是一个标准的递归cte,但有点扭曲.我们添加一个SEQUENCE,它是row_numbers的复合字符串,按顺序排列(在本例中)优先级.
例
Declare @YourTable Table ([Id] varchar(50),[__ParentId] varchar(50),[Priority] varchar(50))
Insert Into @YourTable Values
(1,NULL,NULL)
,(2,1,100)
,(3,1,300)
,(4,1,200)
,(5,4,100)
,(6,4,200)
,(7,6,100)
,(8,5,100)
,(9,5,200)
,(10,9,100)
,(11,5,50)
Declare @Top int = null --<< Sets top of Hier Try 4
Declare @Nest varchar(25) = '|-----' --<< Optional: Added for readability
;with cteP as (
Select Seq = cast(10000+Row_Number() over (Order by [Priority]) as varchar(500))
,ID
,__ParentId
,Lvl=1
,Priority
From @YourTable
Where IsNull(@Top,-1) = case when @Top is null then isnull(__ParentId ,-1) else ID end
Union All
Select Seq = cast(concat(p.Seq,'.',10000+Row_Number() over (Order by r.[Priority])) as varchar(500))
,r.ID
,r.__ParentId
,p.Lvl+1
,r.Priority
From @YourTable r
Join cteP p on r.__ParentId = p.ID)
Select A.ID
,A.__ParentId
,A.Lvl
,A.Priority
,Name = Replicate(@Nest,A.Lvl-1) +cast(ID as varchar(25))
From cteP A
Order By Seq
Run Code Online (Sandbox Code Playgroud)
返回