Pivote de SQL Server 2005 en un número desconocido de columnas
-
03-07-2019 - |
Pregunta
Estoy trabajando con un conjunto de datos que se parecen a los siguientes.
StudentName | AssignmentName | Grade --------------------------------------- StudentA | Assignment 1 | 100 StudentA | Assignment 2 | 80 StudentA | Total | 180 StudentB | Assignment 1 | 100 StudentB | Assignment 2 | 80 StudentB | Assignment 3 | 100 StudentB | Total | 280
El nombre y el número de asignaciones son dinámicos, necesito obtener resultados similares a los siguientes.
Student | Assignment 1 | Assignment 2 | Assignment 3 | Total -------------------------------------------------------------------- Student A | 100 | 80 | null | 180 Student B | 100 | 80 | 100 | 280
Lo ideal sería ordenar la columna según la fecha de vencimiento " que podría ser incluido / asociado con cada tarea. El total debe estar al final si es posible (se puede calcular y eliminar de la consulta si es posible).
Sé cómo hacerlo para las 3 asignaciones usando pivot con solo nombrar las columnas, está intentando hacerlo de una manera dinámica en la que aún no he encontrado una BUENA solución. Estoy tratando de hacer esto en SQL Server 2005
EDIT
Idealmente, me gustaría implementar esto SIN el uso de SQL dinámico, ya que está en contra de la política. Si no es posible ... entonces funcionará un ejemplo funcional con SQL dinámico.
Solución
Sé que usted dijo que no hay SQL
dinámico, pero no veo ninguna manera de hacerlo en SQL
.
Si revisa mis respuestas a problemas similares en Tabla de pivote y Concatenar columnas y PIVOT en SQL 2005
El SQL
dinámico no es vulnerable a la inyección, y no hay una buena razón para prohibirlo. Otra posibilidad (si los datos cambian con poca frecuencia) es hacer generación de código, en lugar de SQL
dinámico, el SQL
se genera en un procedimiento almacenado de forma regular.
Otros consejos
Para PIVOT
esta información usando un sql dinámico puede usar el siguiente código en SQL Server 2005+:
Crear tabla:
CREATE TABLE yourtable
([StudentName] varchar(8), [AssignmentName] varchar(12), [Grade] int)
;
INSERT INTO yourtable
([StudentName], [AssignmentName], [Grade])
VALUES
('StudentA', 'Assignment 1', 100),
('StudentA', 'Assignment 2', 80),
('StudentA', 'Total', 180),
('StudentB', 'Assignment 1', 100),
('StudentB', 'Assignment 2', 80),
('StudentB', 'Assignment 3', 100),
('StudentB', 'Total', 280)
;
PIVOTO dinámico:
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX)
select @cols = STUFF((SELECT distinct ',' + QUOTENAME(AssignmentName)
from yourtable
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query = 'SELECT StudentName, ' + @cols + ' from
(
select StudentName, AssignmentName, grade
from yourtable
) x
pivot
(
min(grade)
for assignmentname in (' + @cols + ')
) p '
execute(@query)
Vea Fiddle de SQL con demostración
El resultado es:
| STUDENTNAME | ASSIGNMENT 1 | ASSIGNMENT 2 | ASSIGNMENT 3 | TOTAL |
--------------------------------------------------------------------
| StudentA | 100 | 80 | (null) | 180 |
| StudentB | 100 | 80 | 100 | 280 |
La única forma que he encontrado para hacer esto es usar SQL dinámico y colocar las etiquetas de columna en una variable.
puede consultar el esquema de información para obtener los nombres y tipos de columna, y luego usar el resultado como una subconsulta cuando construya su conjunto de resultados. Tenga en cuenta que es probable que deba cambiar un poco el acceso de inicio de sesión.
Esto es lo mismo que PIVOT en SQL 2005
Si estos datos son para consumo en un informe, podría utilizar una matriz SSRS. Generará columnas dinámicamente a partir del conjunto de resultados. Lo he usado muchas veces, funciona bastante bien para los informes dinámicos de tablas de referencias cruzadas.
Aquí hay un buen ejemplo con sql dinámico. http: //www.simple- talk.com/community/blogs/andras/archive/2007/09/14/37265.aspx
SELECT TrnType
INTO #Temp1
FROM
(
SELECT '[' + CAST(TransactionType AS VARCHAR(4)) + ']' AS TrnType FROM tblPaymentTransactionTypes
) AS tbl1
SELECT * FROM #Temp1
SELECT * FROM
(
SELECT FirstName + ' ' + LastName AS Patient, TransactionType, ISNULL(PostedAmount, 0) AS PostedAmount
FROM tblPaymentTransactions
INNER JOIN emr_PatientDetails ON tblPaymentTransactions.PracticeID = emr_PatientDetails.PracticeId
INNER JOIN tblPaymentTransactionDetails ON emr_PatientDetails.PatientId = tblPaymentTransactionDetails.PatientID
AND tblPaymentTransactions.TransactionID = tblPaymentTransactionDetails.TransactionID
WHERE emr_PatientDetails.PracticeID = 152
) tbl
PIVOT (SUM(PostedAmount) FOR [TransactionType] IN (SELECT * FROM #Temp1)
) AS tbl4
select studentname,[Assign1],[Assign2],[Assign3],[Total]
from
(
select studentname, assignname, grade from student
)s
pivot(sum(Grade) for assignname IN([Assign1],[Assign2],[Assign3],[Total])) as pvt