SQL Server 2005: поворот на неизвестное количество столбцов
-
03-07-2019 - |
Вопрос
Я работаю с набором данных, который выглядит примерно следующим образом.
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
Имя и количество назначений являются динамическими, мне нужно получить результаты, подобные следующим.
Student | Assignment 1 | Assignment 2 | Assignment 3 | Total -------------------------------------------------------------------- Student A | 100 | 80 | null | 180 Student B | 100 | 80 | 100 | 280
Теперь в идеале я хотел бы отсортировать столбец по «сроку выполнения», который можно было бы включить/связать с каждым заданием.По возможности общая сумма должна быть в конце (ее можно вычислить и удалить из запроса, если это возможно).
Я знаю, как сделать это для трех назначений, используя сводную таблицу, просто называя столбцы, он пытается сделать это динамически, для чего я еще не нашел ХОРОШЕГО решения.Я пытаюсь сделать это на SQL Server 2005.
РЕДАКТИРОВАТЬ
В идеале я хотел бы реализовать это БЕЗ использования динамического SQL, поскольку это противоречит политике.Если это невозможно... тогда подойдет рабочий пример с динамическим SQL.
Решение
Я знаю, ты сказал, что нет динамики SQL
, но я не вижу способа сделать это напрямую SQL
.
Если вы посмотрите мои ответы на подобные проблемы на Сводная таблица и объединение столбцов и ПИВОТ в SQL 2005
Динамика SQL
не уязвим для инъекций, и нет веских причин запрещать это.Другая возможность (если данные меняются очень редко) — делать генерацию кода вместо динамического SQL
, SQL
генерируется в хранимой процедуре на регулярной основе.
Другие советы
К PIVOT
эти данные с использованием динамического sql, вы можете использовать следующий код в SQL Server 2005+:
Создать таблицу:
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)
;
Динамический ПИВОТ:
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)
Видеть SQL-скрипт с демонстрацией
Результат:
| STUDENTNAME | ASSIGNMENT 1 | ASSIGNMENT 2 | ASSIGNMENT 3 | TOTAL |
--------------------------------------------------------------------
| StudentA | 100 | 80 | (null) | 180 |
| StudentB | 100 | 80 | 100 | 280 |
Единственный способ, который я нашел, — это использовать динамический SQL и поместить метки столбцов в переменную.
вы можете запросить information_schema, чтобы получить имена и типы столбцов, а затем использовать результат в качестве подзапроса при построении набора результатов.Обратите внимание, что вам, вероятно, придется немного изменить доступ для входа в систему.
Это то же самое, что ПИВОТ в SQL 2005
Если эти данные предназначены для использования в отчете, вы можете использовать матрицу SSRS.Он будет динамически генерировать столбцы из набора результатов.Я использовал его много раз — он очень хорошо работает для динамических отчетов с перекрестными таблицами.
Вот хороший пример с динамическим SQL.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