SQL分层表:如何跳转级别

时间:2017-04-25 16:16:50

标签: sql-server

我在SQL Server 2008中工作。我需要从表中提取数据(称之为" T")并通过DML(即\/[String, Int]语法)将其加载到另一个表中。表T是一个分层表,定义了4个级别(级别4最低,级别1最高)。表T的基本表结构是:

INSERT INTO ... SELECT ... FROM ...

此表中的每一行都通过parentID(到PK)映射到它上面的级别中的1行。我需要有效地“平坦化”#34;我的CREATE TABLE T ( PK int ,parentID int ,level int ,attribute1 varchar(255) ,attribute2 varchar(255) ,. . . ,attributeN varchar(255) ); 中的表格T.也就是说,对于给定的4级行,我需要从该行中选择一些属性,从相应的2级父级中选择一些属性,从相应的1级父级中选择一些属性。显然,我可以使用SELECT上的JOIN轻松做到这一点。但是,"等级3"父级并不总是存在于每个4级。对于这些情况,4级行直接映射到2级父级。尽管如此,我还是只需要编写一个可以在所有情况下使用的DML模板(3级父级存在且不存在级别)。我怎样才能做到这一点?我的基本查询(我知道错误)是:

parent.PK = child.parentID

2 个答案:

答案 0 :(得分:0)

当缺少level3条目时,我收集你的内部联接失败,并且你不能将level4加入level2到level2,因为这只适用于缺少level3条目的情况。两个查询的联盟是可能的。另一种可能性是通过两个可能的路径连接到level2和level1:

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; 

选择列表现在包括两组可能的属性。对于给定记录,一组属性将为null。您可以使用CASE或COALESCE将其分解为一个选择列表,其中包含您希望看到的任何形式的属性。

答案 1 :(得分: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