2017-06-23 209 views
2

我在SQL Server 2014中工作。我有一個奇怪的數據層次結構情況。 (至少,我以前沒有遇到類似的東西。)SQL複雜的遞歸CTE

在我的層次結構中,有幾個根/最高級別的對象。根級別下的每個對象都映射到其上的一個且僅有一個對象。並非每個節點路徑都是相同的長度。例如,一條路徑可以包含2個對象層次,而另一條路徑可以包含20個對象層次。

層次結構中的每個對象都有一個IsInherited屬性以及一些其他屬性(稱爲SomeAttribute)。 IsInherited屬性指示給定對象是否從最直接的父項繼承SomeAttribute的值。當然,如果一個對象的IsInherited屬性爲'Y',那麼給定的對象從其最直接的父對象繼承值SomeAttribute(這可能會繼承其最直接父對象的值,等等)。否則,指定對象的值爲SomeAttribute

現在,以上所有都不一定非同尋常。這種情況不常見的是這種繼承的具體實現。此層次結構存儲在單個表中(這是否使其成爲鄰接列表模型?),並且如果其IsInherited屬性爲'Y',則爲給定對象/行填充SomeAttribute的值爲而非

我的目標是返回層次結構中所有對象的值SomeAttribute

表的示例如下:

CREATE TABLE hierarchy (
    ID int NOT NULL 
    ,ParentID int NULL 
    ,SomeAttribute char(1) NULL 
    ,IsInherited char(1) NOT NULL 
) 
; 
INSERT INTO hierarchy (ID, ParentID, SomeAttribute, IsInherited) 
VALUES 
(1, NULL, 'a', 'N') 
,(2, NULL, 'b', 'N') 
,(3, NULL, 'c', 'N') 
,(4, NULL, 'd', 'N') 
,(5, NULL, 'e', 'N') 
,(6, NULL, 'f', 'N') 
,(7, NULL, 'g', 'N') 
,(8, 2, NULL, 'Y') 
,(9, 3, 'h', 'N') 
,(10, 4, NULL, 'Y') 
,(11, 5, 'j', 'N') 
,(12, 6, NULL, 'Y') 
,(13, 6, 'k', 'N') 
,(14, 7, 'l', 'N') 
,(15, 7, 'm', 'N') 
,(16, 10, NULL, 'Y') 
,(17, 11, NULL, 'Y') 
,(18, 16, NULL, 'Y') 
,(19, 17, NULL, 'Y') 
,(20, 19, 'o', 'N') 
; 

這給了我們以下節點的路徑:

1 
2-8 
3-9 
4-10-16-18 
5-11-17-19-20 
6-12,13 
7-14,15 

因此,與此示例表,我希望返回:

ID SomeAttribute 
1  a 
2  b 
3  c 
4  d 
5  e 
6  f 
7  g 
8  b (inherited from 2) 
9  h 
10 d (inherited from 4) 
11 j 
12 f (inherited from 6) 
13 k 
14 l 
15 m 
16 d (inherited from 10, inherited from 4) 
17 j (inherited from 11) 
18 d (inherited from 16, inherited from 10, inherited from 4) 
19 j (inherited from 17, inherited from 11) 
20 o 

我知道這可能需要遞歸CTE。我正在努力爲此編寫SQL。我如何返回我想要的輸出?

回答

4

這是鄰接列表模型,因爲每行表示一對相鄰的節點。

和一個遞歸CTE是這樣的:

with q as 
(
    select id, SomeAttribute, cast(id as varchar(max)) SomeAttributePath 
    from hierarchy 
    where ParentID is null 
    union all 
    select c.id, case when c.IsInherited = 'Y' then q.SomeAttribute else c.SomeAttribute end as SomeAttribute, cast(concat(q.SomeAttributePath,'-',c.id) as varchar(max)) 
    from q 
    join hierarchy c 
    on c.ParentID = q.ID 
) 
select * 
from q 
order by id 

Outputing:

id   SomeAttribute SomeAttributePath 
----------- ------------- ----------------- 
1   a    1 
2   b    2 
3   c    3 
4   d    4 
5   e    5 
6   f    6 
7   g    7 
8   b    2-8 
9   h    3-9 
10   d    4-10 
11   j    5-11 
12   f    6-12 
13   k    6-13 
14   l    7-14 
15   m    7-15 
16   d    4-10-16 
17   j    5-11-17 
18   d    4-10-16-18 
19   j    5-11-17-19 
20   o    5-11-17-19-20 
+1

我不得不把投在你的CONCAT,使查詢運行。更重要的是,SomeAttribute中的一些值是錯誤的。例如,20應該是o,而不是e,因爲它的IsInherited標誌是N;同樣,9應該是h。 – user3100444

+0

@ user3100444謝謝。我意外地拒絕了你的編輯,所以手工應用了它的變化。 –

+1

如果您想查看屬性的路徑,僅限於實際從中獲取屬性的路徑,則還可以爲第三列使用一個案例表達式。 'CASE當C.IsInherited ='Y'THEN q.SomeAttributePath +' - 'ELSE''END + CAST(c.id AS VARCHAR(MAX))' –