SQL Server PIVOT on key-value table

No, you can't avoid the aggregate. SQL Server needs some way of combining the many possible rows into one value. You happen to have one value but the PIVOT functionality is made with many rows in mind.

SELECT objectId, [Key 1], [Key 2]
FROM
(SELECT objectId, [key], value FROM ObjectAttributes) AS source
PIVOT
(
 MIN(value)
 FOR [key] IN ([Key 1], [Key 2])
) as pvt

A pivot will be no faster then repeated self joins for a fixed column output.

SELECT
   T1.objectID, T1.Value AS Key1, T2.Value AS Key2
FROM
   ObjectAttributes T1
   JOIN
   ObjectAttributes T2 ON T1.objectID = T2.objectID
WHERE
   T1.key = 'Key 1'
   AND
   T2.key = 'Key 2'

If you want to use PIVOT, then just use MAX. Because you have one row per object/key it's trivial anyway and is there to satisfy the PIVOT requirement.

If you want to PIVOT an unknown number of rows into columns, then it's dynamic SQL (as per SQL Server 2000 solutions) or do it in the client code.

If each object has a fixed number of attributes then I would consider having a 2nd table with real columns maintained by a trigger. Clumsy, but makes life easier for reading


I am adding this answer since this thread is one of the first that appears on Google for this question.

The simplest solution that I have found is to use the combination of max with case, like this:

-- Pivot the data with a handwritten T-SQL statement.
-- Make sure you have an index defined on the grouping column.
SELECT
    RecordID,
    -- Spreading and aggregation phase
    MAX(CASE WHEN Element = 'FirstName' THEN Value END) AS 'FirstName',
    MAX(CASE WHEN Element = 'LastName' THEN Value END) AS 'LastName',
    MAX(CASE WHEN Element = 'City' THEN Value END) AS 'City',
    MAX(CASE WHEN Element = 'Country' THEN Value END) AS 'Country'
FROM EAVTable
GROUP BY RecordID -- Grouping phase

Ref: https://www.sqlpassion.at/archive/2014/08/25/the-dangerous-beauty-of-the-pivot-operator-in-sql-server/

This solution also works pretty much everyone, and you don't need to a lot of join if you need to pivot many columns