Pivot SQL Server 2005 sur un nombre inconnu de colonnes
-
03-07-2019 - |
Question
Je travaille avec un ensemble de données qui ressemble à ce qui suit.
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
Le nom et le nombre d’affectations étant dynamiques, je dois obtenir des résultats identiques à ceux-ci.
Student | Assignment 1 | Assignment 2 | Assignment 3 | Total -------------------------------------------------------------------- Student A | 100 | 80 | null | 180 Student B | 100 | 80 | 100 | 280
Idéalement, j'aimerais trier la colonne en fonction d'une "date d'échéance". qui pourrait être inclus / associé à chaque mission. Le total doit être à la fin si possible (il peut être calculé et supprimé de la requête si possible).
Je sais comment le faire pour les 3 assignations utilisant pivot en nommant simplement les colonnes, c’est essayer de le faire de façon dynamique pour laquelle je n’ai pas encore trouvé de bonne solution. J'essaie de faire cela sur SQL Server 2005
MODIFIER
Idéalement, j'aimerais implémenter ceci SANS utiliser SQL dynamique, car cela est contraire à la politique. Si ce n’est pas possible, un exemple de travail avec Dynamic SQL fonctionnera.
La solution
Je sais que vous avez dit qu'il n'y avait pas de SQL
dynamique, mais je ne vois aucun moyen de le faire en mode SQL
.
Si vous consultez mes réponses à des problèmes similaires à l'adresse table pivot et Concaténer des colonnes et PIVOT dans SQL 2005
Le code SQL
dynamique n’est pas vulnérable à l’injection et il n’ya aucune raison de l’interdire. Une autre possibilité (si les données changent très peu fréquemment) est de générer du code - au lieu de SQL
dynamique, le SQL
est généré régulièrement dans une procédure stockée.
Autres conseils
Pour PIVOT
ces données à l'aide de SQL dynamique, vous pouvez utiliser le code suivant dans SQL Server 2005 +:
Créer un tableau:
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)
;
PIVOT dynamique:
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)
Voir Fiddle SQL avec une démonstration
Le résultat est:
| STUDENTNAME | ASSIGNMENT 1 | ASSIGNMENT 2 | ASSIGNMENT 3 | TOTAL |
--------------------------------------------------------------------
| StudentA | 100 | 80 | (null) | 180 |
| StudentB | 100 | 80 | 100 | 280 |
Le seul moyen que j'ai trouvé de faire cela est d'utiliser du SQL dynamique et de mettre les étiquettes de colonne dans une variable.
vous pouvez interroger information_schema pour obtenir les noms et les types de colonnes, puis utiliser le résultat en tant que sous-requête lorsque vous créez votre jeu de résultats. Notez que vous devrez probablement modifier un peu l'accès à la connexion.
C’est la même chose que PIVOT dans SQL 2005
Si ces données sont destinées à la consommation dans un rapport, vous pouvez utiliser une matrice SSRS. Il générera des colonnes de manière dynamique à partir de l'ensemble de résultats. Je l'ai utilisé à plusieurs reprises - cela fonctionne assez bien pour les rapports d'analyse croisée dynamiques.
Voici un bon exemple avec SQL dynamique. 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