Home > Net >  SQL: Join columns to rows without PIVOT efficiently
SQL: Join columns to rows without PIVOT efficiently

Time:12-29

I have the following two tables. Each Object can have 0-4 corresponding Attributes, which are stored in the Attributes table.

Objects

ID Title
1 Alpha
2 Beta
3 Gamma

Attributes

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

Now I want the following result, where for every possible Attribute a column is created which contains either the corresponing Attribute or NULL.

AttributedObjects

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

I came up with two queries, which produce the wanted result. The database I'm forced to work with doesn't support the PIVOT clause. Under these circumstances, which of the following two is more efficient for the wanted result?

Query based on 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;

Query based on 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;

CodePudding user response:

Use Pivot with 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;  

Demo in db<>fiddle

CodePudding user response:

Use conditional aggregation as follows:

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

CodePudding user response:

I propose one more alternative which seems more efficient using IF or CASE and GROUP BY, so you don't have to pivot anything. Because I don't know what you do with those values, I used SUM. See the following:

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
  • Related