SQL Server 2005 Pivot em Unknown Número de Colunas
-
03-07-2019 - |
Pergunta
Eu estou trabalhando com um conjunto de dados que é algo como o seguinte.
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
O nome e número de atribuições são dinâmica, eu preciso para obter resultados simlilar para o seguinte.
Student | Assignment 1 | Assignment 2 | Assignment 3 | Total -------------------------------------------------------------------- Student A | 100 | 80 | null | 180 Student B | 100 | 80 | 100 | 280
Agora, idealmente, gostaria de classificar a coluna baseada em uma "data de vencimento", que poderia ser incluída / associado a cada tarefa. O total deve estar no final, se possível (Pode ser calculado e removido a partir da consulta, se possível.)
Eu sei como fazê-lo para os 3 trabalhos usando pivô com simplesmente nomear as colunas, que está a tentar fazê-lo de uma forma dinâmica que eu não tenha encontrado uma solução boa para ainda. Eu estou tentando fazer isso em SQL Server 2005
Editar
Idealmente, eu gostaria de implementar isso sem usar SQL dinâmico, como que é contra a política. Se não é possível ... então um exemplo de trabalho com Dynamic SQL vai funcionar.
Solução
Eu sei que você disse que não SQL
dinâmico, mas eu não vejo nenhuma maneira de fazê-lo em SQL
reta.
Se você verificar as minhas respostas para problemas semelhantes em e Colunas concatenar e PIVOT no SQL 2005
O SQL
dinâmica não é vulnerável a injeção, e não há nenhuma boa razão para proibi-la. Outra possibilidade (se os dados está mudando muito raramente) é fazer de geração de código -. Em vez de SQL
dinâmico, o SQL
é gerado para um procedimento armazenado em uma base regular
Outras dicas
Para PIVOT
esses dados usando SQL dinâmico, você pode usar o seguinte código no SQL Server 2005 +:
Criar tabela:
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)
;
Dinâmica PIVOT:
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)
O resultado é:
| STUDENTNAME | ASSIGNMENT 1 | ASSIGNMENT 2 | ASSIGNMENT 3 | TOTAL |
--------------------------------------------------------------------
| StudentA | 100 | 80 | (null) | 180 |
| StudentB | 100 | 80 | 100 | 280 |
A única maneira que eu encontrei para fazer isso é usar SQL dinâmico e colocar os rótulos de coluna em uma variável.
Você pode consultar information_schema para obter os nomes de colunas e tipos, em seguida, usar o resultado como uma subconsulta quando você construir seu conjunto de resultados. Note que você provavelmente terá de alterar o acesso do logon um pouco.
Este é o mesmo que no SQL 2005
Se esses dados é para o consumo em um relatório, você poderia usar uma matriz SSRS. Ele irá gerar colunas dinamicamente a partir de conjunto de resultados. Eu usei-o muitas vezes -. Ele funciona muito bem para relatórios de referência cruzada dinâmica
Aqui está um bom exemplo w / 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