2017-04-25 73 views
0

我正在SQL Server 2008中工作。我需要從表中提取數據(稱爲「T」)並通過DML將其載入另一個表(即,INSERT INTO ... SELECT ... FROM ...語法)。表T是定義了4個級別的分級表(級別4是最低級別,級別1是最高級別)。表T的基本表結構是:SQL分層表:如何跳轉級別

CREATE TABLE T 
(
    PK int 
    ,parentID int 
    ,level int 
    ,attribute1 varchar(255) 
    ,attribute2 varchar(255) 
    ,. 
    . 
    . 
    ,attributeN varchar(255) 
); 

每一行該表中映射到正好1行中通過的parentID(到PK)它上面的水平。我需要在我的SELECT中有效地「展平」表格T.也就是說,對於給定的第4級行,我需要從該行中選擇一些屬性,從其對應的第2級父級中選擇一些屬性,並從其相應第1級父級中選擇一些屬性。很明顯,我可以很容易地用JOINparent.PK = child.parentID上做到這一點。但是,每個級別4行並不總是存在「級別3」父級。對於這些情況,級別4行直接映射到級別2父級。儘管如此,我仍然需要編寫一個可以在所有情況下使用的DML模板(無論是三級父級存在還是不存在)。我怎樣才能做到這一點?我的基本查詢(我知道是錯的)是:

SELECT 
    level4.attribute1 
    ,level2.attributeN 
    ,level1.attribute2 
FROM 
    T AS level4 
INNER JOIN 
    T AS level3 
ON 
    level3.PK = level4.parentID 
INNER JOIN 
    T AS level2 
ON 
    level2.PK = level3.parentID 
INNER JOIN 
    T AS level1 
ON 
    level1.PK = level2.parentID 
WHERE 
    level4.PK = 100 
; 
+1

你在這裏掙扎的原因是因爲你的表缺乏規範化。屬性1,屬性2等被稱爲重複組並違反1NF。你應該擁有一個允許像這樣嵌套的架構。鄰接列表是最常見的處理方法,但嵌套集合更好。或者也有hierarchyid數據類型。無論您需要提供ddl,樣本數據還是所需的輸出。這裏是一個開始的好地方。 http://spaghettidba.com/2015/04/24/how-to-post-a-t-sql-question-on-a-public-forum/ –

回答

0

我收集你內心的加盟級別3項缺少失敗時,你不能內連接到級別4級別2,因爲那樣只會在情況下工作level3條目缺失。兩個查詢的聯合將是可能的。另一種可能性是向左通過對2級以及1級兩種可能的路徑加入自己的方式:

SELECT level4.attribute1, level2.attributeN, altlevel2.attributeN, level1.attribute2, altlevel1.attribute2 
FROM T AS level4 
LEFT JOIN T AS level3 ON level3.PK = level4.parentID 
LEFT JOIN T AS level2 ON level2.PK = level3.parentID 
LEFT JOIN T AS level1 ON level1.PK = level2.parentID 
LEFT JOIN T AS altlevel2 ON level2.PK = level4.parentID 
LEFT JOIN T AS altlevel1 ON level1.PK = level2.parentID 
WHERE level4.PK = 100; 

選擇列表現在包括屬性的兩個可能的套。對於給定記錄,一組屬性將爲空。您可以使用CASE或COALESCE將其歸入具有您想要查看它們的任何形式的屬性的選擇列表中。

0

由於level1是層次結構的頂部,並且不依賴於父ID,因此我會將該原始表並執行左連接。我使用左連接,因爲如果其中一個層缺失,內連接將排除整個層次結構。爲了確保級別不會跳過結果數據集中的級別,我使用每個級別的where子句。否則,您可能會在級別2列中以level3結束,因爲它跳過了parentID level1。這是結果查詢。

DECLARE @T TABLE (
PK INT 
,parentID int 
,level int 
,attribute1 varchar(255) 
,attribute2 varchar(255) 
) 

INSERT @T VALUES 
(1,0,1,'level1','1') 
,(2,0,1,'level1','2') 
,(3,0,1,'level1','3') 
,(4,1,2,'level2','1') 
,(5,2,2,'level2','2') 
,(6,2,2,'level2','3') 
,(7,4,3,'level3','1') 
,(8,5,3,'level3','2') 
,(9,6,3,'level3','3') 
,(10,3,3,'level3','4') 
,(11,9,4,'level4','1') 
,(12,10,4,'level4','2') 


SELECT 
    level1.PK AS L1_PK 
    ,level1.attribute1 AS L1_Attribute1 
    ,level1.attribute2 AS L1_Attribute2 
    ,level2.PK AS L2_PK 
    ,level2.attribute1 AS L2_Attribute1 
    ,level2.attribute2 AS L2_Attribute2 
    ,level3.PK AS L3_PK 
    ,level3.attribute1 AS L3_Attribute1 
    ,level3.attribute2 AS L3_Attribute2 
    ,level4.PK AS L4_PK 
    ,level4.attribute1 AS L4_Attribute1 
    ,level4.attribute2 AS L4_Attribute2 
FROM @T AS level1 
LEFT JOIN @T AS level2 ON 
    level1.PK = level2.parentID 
    AND level2.level = 2 
LEFT JOIN @T AS level3 ON 
    (level2.PK = level3.parentID 
    OR level1.PK = level3.parentID) 
    AND level3.level = 3 
LEFT JOIN @T AS level4 ON 
    (level3.PK = level4.parentID 
    OR level2.PK = level4.parentID 
    OR level1.PK = level4.parentID) 
    AND level4.level = 4 
WHERE level1.level = 1