Sql-Server
如何將 RELATIONAL 數據分解為 HIERARCHY 資料結構?
我有一個返回以下數據集的查詢:
RELATIONid MAPid D1id D2id D3id 4999 4999 626 1250 7 5000 5000 626 1250 8
下一步,我需要將這些數據集綁定到樹視圖(層次結構)中。我需要將此數據集轉換為以下內容:
Nodeid ParentNodeid Header 626 null D1 1250 626 D2 7 1250 D3 8 1250 D3
如何從原始數據集中實現這些結構?
我還有一個問題要問,資料結構比前一個更複雜(一點點)。假設我有這樣的範例數據集:
RELATIONid MAPid D1id D2id D3id 4999 4999 626 1250 7 5000 5000 626 1250 8 5001 5001 627 1300 10 5002 5002 627 1300 12 5003 5003 628 1400 15
從以下數據集中,我們有 3 個 MainParent:
626, 627, 628
並且轉換(交叉應用)輸出期望將是這樣的:Nodeid ParentNodeid Header 626 null D1 1250 626 D2 7 1250 D3 8 1250 D3 627 null D1 1300 627 D2 10 1300 D3 12 1300 D3 628 null D1 1400 628 D2 15 1400 D3
請注意,數據按順序排列,
ParentNode
後跟其節點數據。
交叉申請似乎非常適合這項工作:
SELECT v.Nodeid, v.ParentNodeid, v.Header FROM dbo.atable CROSS APPLY ( VALUES (D1id, NULL, 'D1'), (D2id, D1id, 'D2'), (D3id, D2id, 'D3') ) AS v (Nodeid, ParentNodeid, Header) ;
對於源數據集的每一行,CROSS APPLY 使用 VALUES 行建構子生成三個,明確指定原始集合的哪一列進入哪個新列。
現在,如果源中的某些對重複,則上述內容將返回重複項。您可以使用 DISTINCT 抑制它們:
SELECT **DISTINCT** v.Nodeid, v.ParentNodeid, v.Header ...
為了使轉換後的集合遵循 的順序
D1id ASC, D2id ASC, D3id ASC
,您可以在輸出中包含這些列並將它們用於排序:SELECT DISTINCT **t.D1id, t.D2id, t.D3id,** v.Nodeid, v.ParentNodeid, v.Header FROM dbo.atable AS t CROSS APPLY ( VALUES (t.D1id, NULL , 'D1'), (t.D2id, t.D1id, 'D2'), (t.D3id, t.D2id, 'D3') ) AS v (Nodeid, ParentNodeid, Header) **ORDER BY t.D1id ASC, t.D2id ASC, t.D3id ASC** ;
您必須將它們包含在 SELECT 中的原因是,當您有 DISTINCT 時,您只能按 SELECT 子句中的列進行排序。自然地,結果集也將包括三個額外的列。如果您不希望它們出現在輸出中,則可以將上面的內容用作派生表:您的外部 SELECT 將僅提取三個必需的列並按其他三個列排序:
**SELECT Nodeid, ParentNodeid, Header FROM (** SELECT DISTINCT t.D1id, t.D2id, t.D3id, v.Nodeid, v.ParentNodeid, v.Header FROM dbo.atable AS t CROSS APPLY ( VALUES (t.D1id, NULL , 'D1'), (t.D2id, t.D1id, 'D2'), (t.D3id, t.D2id, 'D3') ) AS v (Nodeid, ParentNodeid, Header) **) AS s ORDER BY D1id ASC, D2id ASC, D3id ASC** ;
或者,您可以使用 GROUP BY 而不是 DISTINCT,從而返回沒有派生表的已排序三列集:
SELECT v.Nodeid, v.ParentNodeid, v.Header FROM dbo.atable AS t CROSS APPLY ( VALUES (t.D1id, NULL , 'D1'), (t.D2id, t.D1id, 'D2'), (t.D3id, t.D2id, 'D3') ) AS v (Nodeid, ParentNodeid, Header) **GROUP BY t.D1id, t.D2id, t.D3id, v.Nodeid, v.ParentNodeid, v.Header** ORDER BY t.D1id ASC, t.D2id ASC, t.D3id ASC ;