2017-04-25 71 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