Esto debería funcionar:
WITH Sales AS (
SELECT
S.SaleID,
S.SoldBy,
S.SalePrice,
S.Margin,
S.Date,
I.SalePrice,
I.Category
FROM
dbo.Sale S
INNER JOIN dbo.SaleItem I
ON S.SaleID = I.SaleID
)
SELECT *
FROM
Sales
PIVOT (Max(SalePrice) FOR Category IN (Books, Printing, DVD)) P
;
O alternativamente:
SELECT
S.SaleID,
S.SoldBy,
S.SalePrice,
S.Margin,
S.Date,
I.Books,
I.Printing,
I.DVD
FROM
dbo.Sale S
INNER JOIN (
SELECT *
FROM
(SELECT SaleID, SalePrice, Category FROM dbo.SaleItem) I
PIVOT (Max(SalePrice) FOR Category IN (Books, Printing, DVD)) P
) I ON S.SaleID = I.SaleID
;
Estos tienen el mismo conjunto de resultados y, de hecho, pueden ser tratados de la misma manera por el optimizador de consultas, pero posiblemente no. La gran diferencia entra en juego cuando empiezas a poner condiciones a la Sale
tabla:debe probar y ver qué consulta funciona mejor.
Nota:es crucial cuando se usa PIVOT
que solo estén disponibles las columnas que deberían formar parte de la salida resultante. Esta es la razón por la que las dos consultas anteriores tienen subconsultas de tablas derivadas adicionales (SELECT ...)
para que solo se expongan columnas específicas. Todas las columnas que están disponibles para ser vistas por PIVOT
que no se enumeran en la expresión dinámica se agruparán implícitamente y se incluirán en el resultado final. Es probable que esto no sea lo que quieres.
Sin embargo, ¿puedo sugerir que haga el pivote en la capa de presentación? Si, por ejemplo, está usando SSRS, es bastante fácil usar un control de matriz que hará todo el pivote por usted. Eso es lo mejor, porque si agrega una nueva Category
, ¡no tendrás que modificar todo tu código SQL!
Hay una manera de encontrar dinámicamente los nombres de las columnas para pivotar, pero involucra SQL dinámico. Realmente tampoco lo recomiendo como la mejor manera, aunque es posible.
Otra forma en que podría el trabajo sería preprocesar esta consulta, lo que significa establecer un disparador en la Category
tabla que reescribe una vista para contener todas las categorías existentes. Esto resuelve muchos de los otros problemas que he mencionado, pero nuevamente, usar la capa de presentación es lo mejor.
Nota :si los nombres de sus columnas (que anteriormente eran valores) tienen espacios, son números o comienzan con un número, o no son identificadores válidos, debe citarlos entre corchetes como en PIVOT (Max(Value) FOR CategoryId IN ([1], [2], [3], [4])) P
. Alternativamente, puede modificar los valores antes de que lleguen al PIVOT
parte de la consulta para anteponer algunas letras o eliminar espacios, de modo que no sea necesario escapar de la lista de columnas. Para leer más sobre esto, consulte las reglas para identificadores en SQL Server.