自左加入重复
Duplicates on Self Left Join
我正在尝试将存储在垂直模型中的 table 数据转换为更水平的、类似于 SQL 服务器 table 的模型。不幸的是,由于数据的性质,我不能在这里使用真实数据,所以我设计了一个遵循相同模型的通用示例。
table一共有三列,ID,列ID和值,其中ID和列ID构成Primary Key。另外 none 的数据是必需的(即 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 去除这些重复项,但数据集相当大,因此所需的排序操作极大地减慢了查询速度。有没有更好的方法来完成这个,还是我只是遇到了一个缓慢的查询?
我不明白你对排序的担忧。你有一个主键,所以你也有一个索引。正确的做法是:
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
您可以使用 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
会出问题
如果您愿意,您可以使用枢轴..
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
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
您的问题是您正在加入具有多行的主 table。
我正在尝试将存储在垂直模型中的 table 数据转换为更水平的、类似于 SQL 服务器 table 的模型。不幸的是,由于数据的性质,我不能在这里使用真实数据,所以我设计了一个遵循相同模型的通用示例。
table一共有三列,ID,列ID和值,其中ID和列ID构成Primary Key。另外 none 的数据是必需的(即 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 去除这些重复项,但数据集相当大,因此所需的排序操作极大地减慢了查询速度。有没有更好的方法来完成这个,还是我只是遇到了一个缓慢的查询?
我不明白你对排序的担忧。你有一个主键,所以你也有一个索引。正确的做法是:
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
您可以使用 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
如果您愿意,您可以使用枢轴..
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
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
您的问题是您正在加入具有多行的主 table。