Jak mówili inni, można użyć obrotowe i operatorów UNPIVOT. Niestety, jednym z problemów zarówno z PIVOT jak i UNPIVOT jest to, że musisz znać wartości, z którymi będziesz się obracał wcześniej lub używał dynamicznego SQL.
Wygląda na to, że w twoim przypadku będziesz musiał użyć dynamicznego SQL. Aby to działało dobrze, musisz pobrać listę produktów używanych w zapytaniu. Jeśli korzystasz z bazy danych AdventureWorks, Twój kod będzie wyglądać następująco:
USE AdventureWorks;
GO
DECLARE @columns NVARCHAR(MAX);
SELECT x.ProductName
INTO #products
FROM (SELECT p.[Name] AS ProductName
FROM Purchasing.Vendor AS v
INNER JOIN Purchasing.PurchaseOrderHeader AS poh ON v.VendorID = poh.VendorID
INNER JOIN Purchasing.PurchaseOrderDetail AS pod ON poh.PurchaseOrderID = pod.PurchaseOrderID
INNER JOIN Production.Product AS p ON pod.ProductID = p.ProductID
GROUP BY p.[Name]) AS x;
SELECT @columns = STUFF(
(SELECT ', ' + QUOTENAME(ProductName, '[') AS [text()]
FROM #products FOR XML PATH ('')
), 1, 1, '');
SELECT @columns;
Teraz masz swoje kolumny, można wyciągnąć wszystko co trzeba obracać na z dynamicznym kwerendy:
DECLARE @sql NVARCHAR(MAX);
SET @sql = 'SELECT CustomerName, ' + @columns + '
FROM (
// your query goes here
) AS source
PIVOT (SUM(order_count) FOR product_name IN (' + @columns + ') AS p';
EXEC sp_executesql @sql
Oczywiście, jeśli chcesz mieć pewność, że uzyskasz przyzwoite wartości, być może będziesz musiał skopiować logikę, której używasz do budowania kolumn @ i utworzyć zmienną @coalesceColumns, która będzie przechowywać kod do COALESCE (col_name, 0), jeśli potrzebujesz tego rodzaju rzeczy w twoim zapytaniu.