2016-01-11 67 views
-1

我试图将存储在垂直模型中的数据表转换为更加水平的SQL Server类表模型。不幸的是,由于数据的性质,我不能在这里使用真实的数据,所以我编写了一个遵循相同模型的通用示例。自左连接重复

表中有三列,即ID,列ID和值,其中ID和列ID构成主键。此外,需要没有数据(即一个ID可以缺少列ID = 3不破坏任何东西)

PetID | ColumnID | Value 
--------------------------- 
1  | 1  | Gilda 
1  | 2  | Cat 
2  | 1  | Sonny 
2  | 2  | Cat 
2  | 3  | Black 

由于这样的事实,主键是两列的复合,我不能使用内置的PIVOT功能,所以我尝试做一个自我LEFT JOIN:

SELECT T1.PetID 
    ,T2.Value AS [Name] 
    ,T3.Value AS [Type] 
    ,T4.Value AS [Color] 
FROM @Temp AS T1 
LEFT JOIN @Temp AS T2 ON T1.PetID = T2.PetID 
    AND T2.ColumnID = 1 
LEFT JOIN @Temp AS T3 ON T1.PetID = T3.PetID 
    AND T3.ColumnID = 2 
LEFT JOIN @Temp AS T4 ON T1.PetID = T4.PetID 
    AND T4.ColumnID = 3; 

的想法是,我想借此从T1的ID,然后做一个自我LEFT JOIN通过ColumnID的获得每个值。但是我得到的重复数据:

PetID | Name | Type | Color 
------------------------------ 
1  | Gilda | Cat | NULL 
1  | Gilda | Cat | NULL 
2  | Sonny | Cat | Black 
2  | Sonny | Cat | Black 
2  | Sonny | Cat | Black 

我能够摆脱使用DISTINCT这些重复的,但该数据集是相当大的,因此所需要的那种动作大大减慢查询。有没有更好的方法来完成这个或我只是坚持一个缓慢的查询?

+0

确实有更好的方法来完成加入部分,但我确实相信GROUP BY比DISTINCT快,您可以使用它来删除重复项。 – GendoIkari

+1

@GendoIkari,true,但GROUP BY仍然会在后台使用排序并减慢查询速度。我真的很想找一个更有效的方法来做这些连接,但是谢谢你的建议。 –

+0

加入会带来更多的行,但你有一些有趣的答案来解决加入 – Paparazzi

回答

1

您可以使用CASE语句,避免使用加入。

SELECT 
    PetID, 
    MAX(CASE WHEN ColumnID = 1 THEN Value ELSE NULL END) AS Name, 
    MAX(CASE WHEN ColumnID = 2 THEN Value ELSE NULL END) AS Type, 
    MAX(CASE WHEN ColumnID = 3 THEN Value ELSE NULL END) AS Color 
FROM @Temp 
GROUP BY PetId 

PetID, ColumnID是正确工作的主要关键,这是至关重要的。否则当同一ColumnID多次使用它会导致问题同样PetID

+0

我会试试这个。感谢您的建议! –

+0

我尝试了几个提供的答案,这个提供了真实数据中最快的执行时间。 –

0

我不明白你对排序的关注。你有一个主键,所以你也有一个索引。这是做正确的方法:

select 
    PetID, 
    min(case when ColumnID = 1 then Value end) as Name, 
    min(case when ColumnID = 2 then Value end) as Type, 
    min(case when ColumnID = 3 then Value end) as Color 
from @Temp 
group by PetID 

一个你复制的解决方法是,虽然简单,可能会提高性能,以及:

FROM (select distinct PetID from @Temp) AS T1 
+0

排序问题是SQL Server的代价高昂的操作,并会降低查询执行速度,特别是对于大型数据集。我的例子只是一个小样本,因为我的完整数据集非常大。除非绝对需要,否则通常认为最佳做法是避免排序。 –

+0

您的数据已经排序,因为您已定义主键。无论如何,四路连接如何比单次扫描更快? – shawnt00

1

可以,如果你想使用枢轴..

SELECT * 
FROM (SELECT PetID, 
       (CASE ColumnID 
        WHEN 1 THEN 'Name' 
        WHEN 2 THEN 'Type' 
        WHEN 3 THEN 'Color' 
       END) ValueType, 
       VALUE 
     FROM @Temp 
     ) t 
PIVOT 
( MAX(Value) 
    FOR ValueType IN ([Name],[Type],[Color]) 
) p 

无子查询另一种方法是..

SELECT PetID, 
     [1] [Name], 
     [2] [Type], 
     [3] [Color] 
FROM @Temp 
PIVOT 
( MAX(Value) 
    FOR ColumnID IN ([1],[2],[3]) 
) p 
+0

非常有趣!我会试试这个。感谢您的建议。 –

+0

我试着用真实的数据来试试这个,而另一个答案最终变得更快,但这是在未来查询中使用的好信息。 –

0
SELECT T1.PetID 
    ,T1.Value AS [Name] 
    ,T2.Value AS [Type] 
    ,T3.Value AS [Color] 
    --select * 
FROM #Temp AS T1 
LEFT JOIN #Temp AS T2 ON T1.PetID = T2.PetID 
    AND T2.ColumnID = 2 
LEFT JOIN #Temp AS T3 ON T1.PetID = T3.PetID 
    AND T3.ColumnID = 3 
where t1.ColumnID = 1 

你的问题是,你加入到具有多行主表。