Sql-Server

如何將 RELATIONAL 數據分解為 HIERARCHY 資料結構?

  • September 23, 2017

我有一個返回以下數據集的查詢:

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
;

引用自:https://dba.stackexchange.com/questions/106538