SQL:在没有 PIVOT 的情况下有效地将列连接到行

SQL: Join columns to rows without PIVOT efficiently

我有以下两个table。每个Object可以有0-4个对应的Attributes,存储在Attributestable.

对象

ID Title
1 Alpha
2 Beta
3 Gamma

属性

ID ObjectID AttributeName AttributeValue
1 1 K1 12345
2 1 K2 23456
3 2 K1 34567
4 3 K2 45678
5 3 K3 56789
6 3 K4 67890

现在我想要以下结果,其中为每个可能的属性创建一个包含相应属性或 NULL 的列。

属性对象

ID Title K1 K2 K3 K4
1 Alpha 12345 23456
2 Beta 34567
3 Gamma 45678 56789 67890

我想出了两个查询,它们产生了想要的结果。我被迫使用的数据库 不支持 PIVOT 子句 。在这种情况下,对于想要的结果,以下两个中哪个更有效?

查询基于SELECT

SELECT ID, Title,
    (SELECT AttributeValue FROM Attributes WHERE AttributeName = "K1" AND ObjectID = Objects.ID) AS K1,
    (SELECT AttributeValue FROM Attributes WHERE AttributeName = "K2" AND ObjectID = Objects.ID) AS K2,
    (SELECT AttributeValue FROM Attributes WHERE AttributeName = "K3" AND ObjectID = Objects.ID) AS K3,
    (SELECT AttributeValue FROM Attributes WHERE AttributeName = "K4" AND ObjectID = Objects.ID) AS K4
FROM Objects;

基于 JOIN 的查询

SELECT Objects.ID, Objects.Title, Q1.K1, Q2.K2, Q3.K3, Q4.K4
FROM (((Objects 
    LEFT JOIN (SELECT ObjectID, AttributeValue AS K1 FROM Attributes WHERE AttributeName = "K1")
        AS Q1 ON Objects.ID = Q1.ObjectID)
    LEFT JOIN (SELECT ObjectID, AttributeValue AS K2 FROM Attributes WHERE AttributeName = "K2")
        AS Q2 ON Objects.ID = Q2.ObjectID)
    LEFT JOIN (SELECT ObjectID, AttributeValue AS K3 FROM Attributes WHERE AttributeName = "K3")
        AS Q3 ON Objects.ID = Q3.ObjectID)
    LEFT JOIN (SELECT ObjectID, AttributeValue AS K4 FROM Attributes WHERE AttributeName = "K4")
        AS Q4 ON Objects.ID = Q4.ObjectID;

使用 PivotJoin

SELECT ID,Title, 
  K1,K2,K3,K4  
FROM  
(
  SELECT o.ID,Title,AttributeName, AttributeValue   
  FROM Objects o
  JOIN Attributes a ON o.ID = a.ObjectID
) AS SourceTable  
PIVOT  
(  
  AVG(AttributeValue)  
  FOR AttributeName IN (K1,K2,K3,K4)  
) AS PivotTable;  

演示在 db<>fiddle

我提出了另一种替代方法,使用 IFCASEGROUP BY 似乎更有效,因此您无需调整任何内容。因为我不知道你用这些值做什么,所以我使用了 SUM。请参阅以下内容:

SELECT Title,
       SUM(IF(AttributeName = 'K1', AttributeValue, 0)) AS K1,
       SUM(IF(AttributeName = 'K2', AttributeValue, 0)) AS K2,
       SUM(IF(AttributeName = 'K3', AttributeValue, 0)) AS K3,
       SUM(IF(AttributeName = 'K4', AttributeValue, 0)) AS K4
FROM AttributedObjects AS AO
INNER JOIN Attributes AS A ON AO.ObjectID = O.ID
GROUP BY Title

使用conditional aggregation如下:

select o.id, o.title,
    Max(case when AttributeName='K1' then AttributeValue end) K1,
    Max(case when AttributeName='K2' then AttributeValue end) K2,
    Max(case when AttributeName='K3' then AttributeValue end) K3,
    Max(case when AttributeName='K4' then AttributeValue end) K4
from objects o
join attributes a on a.ObjectID = o.id
group by o.Id, o.title