我试图将存储在垂直模型中的数据表转移到更加水平的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功能,所以我尝试自我左键连接:
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 :(得分: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
时,会导致问题
答案 1 :(得分: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
没有Sub查询的另一种方法是..
SELECT PetID,
[1] [Name],
[2] [Type],
[3] [Color]
FROM @Temp
PIVOT
( MAX(Value)
FOR ColumnID IN ([1],[2],[3])
) p
答案 2 :(得分:0)
我不了解您对排序的担忧。你有一个主键,所以你也有一个索引。这是正确的方法:
FROM (select distinct PetID from @Temp) AS T1
复制的修复很简单,但也可能会提高性能:
{{1}}
答案 3 :(得分: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
您的问题是您正在加入具有多行的主表。