簡體   English   中英

SQL:具有n級的層次結構

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM