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;
使用 Pivot
和 Join
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
我提出了另一种替代方法,使用 IF
或 CASE
和 GROUP 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
我有以下两个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;
使用 Pivot
和 Join
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
我提出了另一种替代方法,使用 IF
或 CASE
和 GROUP 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