自左加入重复

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。