6

我在SQL Server下表(2012年):SQL Server的CTE和訂貨

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  

__ParentId列引用標識知道父母的任何一行,它可以下降到很多級別的遞歸(例如,Id 85的孩子,它是4的孩子,它是的孩子0)。

此外,還有一個優先列顯示孩子應該出現在父母(最低數量獲得優先)的順序。

所以,最後的表我想獲得的是:

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  

爲了解釋觸摸,我們有21一個孩子,具有最高的優先級,但一直沒有孩子,所以,我們在那裏停留,然後4是下一個優先的孩子,所以它接下來,但是然後我們根據優先級和等級分化爲它的孩子和他們的孩子。

或者,通過樹形結構來解釋:

1 
    2 
    4 
     5 
      11 
      8 
      9 
       10 
     6 
      7 
    3 

我可以創建CTE,這將使我父母的孩子,但我不能想出一個好辦法,以獲得正確的排序,所以甚至不能提供我一直在嘗試的好SQL。

回答

8

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 

結果:

enter image description here

Demo

說明#1:該解決方案使用HIERARCHYID排序的一個屬性:HID值是使用深度優先的方式排序(這意味着父和那麼所有的孩子)。

給定兩個等級值a和b,小於b意味着a在樹的深度優先遍歷中位於b之前。等級數據類型 上的索引處於深度優先的順序,並且彼此靠近的節點彼此靠近地存儲在深度優先遍歷中。例如,記錄的 子項存儲在該記錄的旁邊。有關更多 信息,請參閱分層數據(SQL Server)。

Reference

+0

不錯 - 從來沒有考慮過我可以將第二個元素添加到層次結構ID +1 –

+0

這個解決方案也嚇壞了美麗! - **非常感謝** - 我從來沒有想過/知道要做一個實際的文本串聯,它是** BRILLIANT **。這也同樣適用,我不能將你標記爲解決方案的唯一原因是因爲我必須選擇一個,約翰回答得更快......儘管我真的不能夠感謝你! –

+0

@JohnBus​​tos接受最適合你的答案。 –

6

這是一個標準的遞歸cte,但有點扭曲。我們添加一個SEQUENCE這是一個複合字符串row_numbers order(在這種情況下)的優先級。

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 

返回

enter image description here

+1

就 - 哇!!!! - 現在就試試看,但是**謝謝!!! ** –

+1

我知道它的工作完美....真的不能夠感謝你了!!!!! –

+0

@JohnBus​​tos對此有幫助 –