[英]SQL: Hierarchical structure with n level
我有一個存儲在以樹狀視圖表示的關系數據庫中的層次結構。 每個節點都有其屬性的各個字段,並通過ID知道其父節點。 這是一個父子關系模型。
如果節點有子節點,則該節點的名稱前會以[+]表示。 通過單擊[+],可以展開節點並查看節點的子級。 如果子節點具有最低級別,則子節點本身具有[+]。
一個簡化的樹視圖示例如下所示:
[+] A Land
[+] A.1 Car
A.1.A Motor
A.1.B Wheels
[+] B Sea
B.1 Sailing ship
[+] B.2 Motorboat
B.2.A Motor
[+] C Air
[+] C.1 Plane
C.1.A Turbine
C.2.B Wheels
可以在各種節點屬性上設置一個或多個過濾器,例如,顯示所有后代名為“ Motor”的節點。 樹視圖如下所示:
[+] A Land
[+] A.1 Car
A.1.A Motor
[+] B Sea
[+] B.2 Motorboat
B.2.A Motor
由於級別數和節點數有限,因此該結構可以滿足我的需求(性能中等)。
現在,我們想將樹視圖擴展到n級深度。
有嵌套的集模型,只要不過濾掉內容,性能就很好。 據我們所知,這是因為嵌套集不支持過濾。 我們還嘗試了路徑模型(SQL-Serversarchitectureid-datatype),但是如果級別很多,則過濾速度很慢。
我們的路徑模型方法:假設您在tbale PMTable中的每個級別中有20個級別,其中每個節點都有很多節點,並且該字段的“ Path”列為hierarchicalid-datatype。 然后,您將不查詢(初始化TreeView)具有至少一個后代(必須不是直接后代,descandant可以具有每個可能的級別)的所有頂級節點,這些節點適用於過濾器(例如:name如'%motor%'AND類型= 3,其中名稱和類型是同一路徑模型表中的列)。 我們還存儲了從零開始的節點級別,以簡化查詢。
查詢可以是:
SELECT id, name
FROM PMTable WHERE level = 0
AND Path IN
(
SELECT Path WHERE Path.GetAncestor(Path.GetLevel() - 1)
FROM PMTable
WHERE name LIKE '%motor%' AND type = 3
)
ORDER BY name
該查詢的性能可能中等,但是如您所見,在頂級查詢中,您還有一個昂貴的子查詢,該子查詢必須查詢表中符合條件的所有節點。
但是,如果用戶單擊小[+]擴展一個頂級節點,則必須查詢所有第二級節點,該第二級節點具有被單擊的節點作為祖先,並且還匹配該過濾條件(包含匹配的任何級別的去掃描劑)。 如果節點本身符合該過濾條件(類型為3,名稱包括“ motor”),則必須顯示其所有后代。
在我們的示例中,這些查詢的性能很差。
是否有您更喜歡的其他模型,或為此獲得更好性能的一些想法。
謝謝!
在過去的20年中,我一直在為層次結構使用范圍鍵。 我們擁有大量的替代層次結構,這些層次結構已用於報告,處理和/或選擇標准。 我還創建了一個用於快速導航和實用程序的函數庫。
以下是一個快速示例。 請記住,我手動創建了范圍鍵,它們通常是通過編程方式創建/更新的。 另外,我通常會使用一個演示序列號來在歸因期間按級別控制實際序列。
真正的好處是,您可以輕松地聚合可變深度數據,而無需使用遞歸查詢。
下面的查詢缺少我的所有助手,因為我想說明這種技術。
Declare @OH table (OH_R1 int,OH_R2 int,OH_Lvl int,OH_Nr int,OH_Pt int,OH_Title varchar(100))
Insert into @OH Select 0,12,1,9,0,'Total'
Insert into @OH Select 1,4,2,100,9,'Land'
Insert into @OH Select 2,4,3,200,100,'Car'
Insert into @OH Select 3,3,4,300,200,'Motor'
Insert into @OH Select 4,4,4,400,200,'Wheels'
Insert into @OH Select 5,8,2,500,9,'Sea'
Insert into @OH Select 6,6,3,600,500,'Sailing Ship'
Insert into @OH Select 7,8,3,625,500,'Motor Boat'
Insert into @OH Select 8,8,4,650,625,'Motor'
Insert into @OH Select 9,12,2,800,9,'Air'
Insert into @OH Select 10,12,3,825,800,'Plane'
Insert into @OH Select 11,11,4,550,825,'Turbine'
Insert into @OH Select 12,12,4,550,825,'Wheele'
-- Show Nested/Filtered Hierarchy
Select A.*
,Nested=Replicate(' ',OH_Lvl-1)+OH_Title
,Hits=sum(hits)
From @OH A
Join (Select OH_R1,Hits=1 from @OH where OH_Title like '%motor%' and OH_Lvl=4) B on (B.OH_R1 between A.OH_R1 and A.OH_R2)
Group by A.OH_R1,A.OH_R2,A.OH_Lvl,A.OH_Nr,A.OH_Pt,A.OH_Title
Order by OH_R1
-- Show Actual Hierarchy
Select * from @OH Order by OH_R1
退貨
OH_R1 OH_R2 OH_Lvl OH_Nr OH_Pt OH_Title Nested Hits
0 12 1 9 0 Total Total 2
1 4 2 100 9 Land Land 1
2 4 3 200 100 Car Car 1
3 3 4 300 200 Motor Motor 1
5 8 2 500 9 Sea Sea 1
7 8 3 625 500 Motor Boat Motor Boat 1
8 8 4 650 625 Motor Motor 1
從SQL Server 2005開始,T-SQL開發人員能夠使用CTE結構執行遞歸查詢以獲取層次結構數據
如果您查看了所引用的SQL教程,則會在最后的屏幕截圖中找到示例數據,示例CTE查詢和層次結構級別
在SQL Server中,遞歸CTE的形成如下
WITH cte AS (
{Anchor_Query}
UNION ALL
{Recursive part joining to cte}
)
SELECT * FROM cte
通過在CTE的anchor Select語句中將層次結構的初始級別添加為1,並在遞歸部分中將該級別增加1,您最終將最終得到結果數據集中的所有層次結構級別
請檢查示例SQL教程
使用嵌套集模型,查找所有后代名為“ Motor”的樹應該非常簡單:
SELECT
P.name -- Or whatever other columns you need
FROM
My_Tree D
INNER JOIN My_Tree P ON P.lft <= D.lft AND P.rgt >= D.rgt
WHERE
D.name = 'Motor'
如果您還希望包括該節點的后代(即,任何成員都具有該名稱的完整樹),則可以輕松添加一個OR
語句來獲取子節點。
非常感謝您的努力。 您真的很有幫助。 我們提出了路徑模型和遞歸CTE的組合,並在表中額外插入了父代ID,以提高性能。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.