Sé que esta pregunta es más antigua, pero estaba buscando las respuestas y pensé que podría ampliar la parte "dinámica" del problema y posiblemente ayudar a alguien.
En primer lugar, construí esta solución para resolver un problema que un par de compañeros de trabajo estaban teniendo con conjuntos de datos grandes e inconstantes que debían pivotar rápidamente.
Esta solución requiere la creación de un procedimiento almacenado, por lo que si eso no se ajusta a sus necesidades, deje de leer ahora.
Este procedimiento tomará las variables clave de una declaración dinámica para crear dinámicamente declaraciones dinámicas para diferentes tablas, nombres de columnas y agregados. La columna estática se usa como la columna de grupo por / identidad para el pivote (esto puede eliminarse del código si no es necesario, pero es bastante común en las declaraciones de pivote y fue necesario para resolver el problema original), la columna pivote es donde se generarán los nombres de columna resultantes finales, y la columna de valor es a lo que se aplicará el agregado. El parámetro Table es el nombre de la tabla, incluido el esquema (schema.tablename), esta parte del código podría usar algo de amor porque no es tan limpio como me gustaría que fuera. Funcionó para mí porque mi uso no era público y la inyección de sql no era una preocupación.
Comencemos con el código para crear el procedimiento almacenado. Este código debería funcionar en todas las versiones de SSMS 2005 y superiores, pero no lo he probado en 2005 o 2016, pero no puedo ver por qué no funcionaría.
create PROCEDURE [dbo].[USP_DYNAMIC_PIVOT]
(
@STATIC_COLUMN VARCHAR(255),
@PIVOT_COLUMN VARCHAR(255),
@VALUE_COLUMN VARCHAR(255),
@TABLE VARCHAR(255),
@AGGREGATE VARCHAR(20) = null
)
AS
BEGIN
SET NOCOUNT ON;
declare @AVAIABLE_TO_PIVOT NVARCHAR(MAX),
@SQLSTRING NVARCHAR(MAX),
@PIVOT_SQL_STRING NVARCHAR(MAX),
@TEMPVARCOLUMNS NVARCHAR(MAX),
@TABLESQL NVARCHAR(MAX)
if isnull(@AGGREGATE,'') = ''
begin
SET @AGGREGATE = 'MAX'
end
SET @PIVOT_SQL_STRING = 'SELECT top 1 STUFF((SELECT distinct '', '' + CAST(''[''+CONVERT(VARCHAR,'+ @PIVOT_COLUMN+')+'']'' AS VARCHAR(50)) [text()]
FROM '+@TABLE+'
WHERE ISNULL('+@PIVOT_COLUMN+','''') <> ''''
FOR XML PATH(''''), TYPE)
.value(''.'',''NVARCHAR(MAX)''),1,2,'' '') as PIVOT_VALUES
from '+@TABLE+' ma
ORDER BY ' + @PIVOT_COLUMN + ''
declare @TAB AS TABLE(COL NVARCHAR(MAX) )
INSERT INTO @TAB EXEC SP_EXECUTESQL @PIVOT_SQL_STRING, @AVAIABLE_TO_PIVOT
SET @AVAIABLE_TO_PIVOT = (SELECT * FROM @TAB)
SET @TEMPVARCOLUMNS = (SELECT replace(@AVAIABLE_TO_PIVOT,',',' nvarchar(255) null,') + ' nvarchar(255) null')
SET @SQLSTRING = 'DECLARE @RETURN_TABLE TABLE ('+@STATIC_COLUMN+' NVARCHAR(255) NULL,'+@TEMPVARCOLUMNS+')
INSERT INTO @RETURN_TABLE('+@STATIC_COLUMN+','+@AVAIABLE_TO_PIVOT+')
select * from (
SELECT ' + @STATIC_COLUMN + ' , ' + @PIVOT_COLUMN + ', ' + @VALUE_COLUMN + ' FROM '+@TABLE+' ) a
PIVOT
(
'+@AGGREGATE+'('+@VALUE_COLUMN+')
FOR '+@PIVOT_COLUMN+' IN ('+@AVAIABLE_TO_PIVOT+')
) piv
SELECT * FROM @RETURN_TABLE'
EXEC SP_EXECUTESQL @SQLSTRING
END
A continuación, prepararemos nuestros datos para el ejemplo. Tomé el ejemplo de datos de la respuesta aceptada con la adición de un par de elementos de datos para usar en esta prueba de concepto para mostrar los resultados variados del cambio agregado.
create table temp
(
date datetime,
category varchar(3),
amount money
)
insert into temp values ('1/1/2012', 'ABC', 1000.00)
insert into temp values ('1/1/2012', 'ABC', 2000.00) -- added
insert into temp values ('2/1/2012', 'DEF', 500.00)
insert into temp values ('2/1/2012', 'DEF', 1500.00) -- added
insert into temp values ('2/1/2012', 'GHI', 800.00)
insert into temp values ('2/10/2012', 'DEF', 700.00)
insert into temp values ('2/10/2012', 'DEF', 800.00) -- addded
insert into temp values ('3/1/2012', 'ABC', 1100.00)
Los siguientes ejemplos muestran las declaraciones de ejecución variadas que muestran los agregados variados como un ejemplo simple. No opté por cambiar las columnas estáticas, dinámicas y de valor para mantener el ejemplo simple. Debería poder simplemente copiar y pegar el código para comenzar a jugarlo usted mismo
exec [dbo].[USP_DYNAMIC_PIVOT] 'date','category','amount','dbo.temp','sum'
exec [dbo].[USP_DYNAMIC_PIVOT] 'date','category','amount','dbo.temp','max'
exec [dbo].[USP_DYNAMIC_PIVOT] 'date','category','amount','dbo.temp','avg'
exec [dbo].[USP_DYNAMIC_PIVOT] 'date','category','amount','dbo.temp','min'
Esta ejecución devuelve los siguientes conjuntos de datos respectivamente.