我使用以下SQL(使用SQL Server 2016)来透射LMS(Moodle)的测试结果列表:
SELECT *
FROM
(SELECT
u.firstname AS name,
u.lastname AS last_name,
u.idnumber AS id_number,
gi.itemname AS exam_name,
CAST(gg.finalgrade / gi.grademax * 100 AS integer) AS grade
FROM
mdl_grade_grades gg
INNER JOIN
mdl_grade_items gi ON gg.itemid = gi.id
INNER JOIN
mdl_course c ON gi.courseid = c.id
INNER JOIN
mdl_user u ON gg.userid = u.id
WHERE
(gi.itemname IS NOT NULL)
AND (gi.courseid = 123)) SOURCE
PIVOT
(MAX(grade)
FOR exam_name IN ([Exam ABC], [Exam DEF], [Exam GHI],
[Exam JKL], [Exam XYZ])
) PIVT
ORDER BY
id_number
结果将是:
name last name id number division region branch Exam ABC Exam DEF Exam GHI Exam JKL Exam XYZ
John Tester 3343664 ABC WEST RGN A AGY 65 44
Kenny Quipton 4342423 DDA CENTRAL RGN FRN 88 66 90 89
Molefi Manase 5456545 CCS ABC RGN XXX SOL 74 90 85 80 77
我唯一的问题是考试名称必须在FOR IN(...)
列表中进行硬编码,因此每次更改内容时都必须手动更新列表。
可以使用动态SQL重写此SQL吗?
更好的是 - 使用Stuff()
或FOR XML PATH
还是其他什么?
我无法使用存储过程(应用程序不支持它们)。
答案 0 :(得分:0)
不需要存储过程和FOR XML Path用于逗号连接。 只需将以下代码放入查询构建器并将其发送到数据库服务器即可。
DECLARE @SQL VARCHAR(MAX)='', @COL_NAMES VARCHAR(MAX)='';
--PREPARING EXAM NAMES LIST
SELECT @COL_NAMES = @COL_NAMES+ itemname+',' FROM (
SELECT DISTINCT gi.itemname
FROM mdl_grade_grades gg
INNER JOIN mdl_grade_items gi ON gg.itemid = gi.id
INNER JOIN mdl_course c ON gi.courseid = c.id
INNER JOIN mdl_course_categories cc ON c.category = cc.id
INNER JOIN mdl_user u ON gg.userid = u.id
WHERE (gi.itemname IS NOT NULL)
AND (gi.courseid = 123)
);
SELECT @COL_NAMES = LEFT(@COL_NAMES,LEN(@COL_NAMES)-1 );
--PREPARING DYNAMIC QUERY
SELECT @SQL =
'SELECT * FROM (
SELECT
u.firstname AS name,
u.lastname AS last_name,
u.idnumber AS id_number,
gi.itemname AS exam_name,
CAST(gg.finalgrade / gi.grademax * 100 AS integer) AS grade
FROM mdl_grade_grades gg
INNER JOIN mdl_grade_items gi ON gg.itemid = gi.id
INNER JOIN mdl_course c ON gi.courseid = c.id
INNER JOIN mdl_course_categories cc ON c.category = cc.id
INNER JOIN mdl_user u ON gg.userid = u.id
WHERE (gi.itemname IS NOT NULL)
AND (gi.courseid = 123)
) SOURCE
PIVOT (
MAX(grade)
FOR exam_name IN ('+@COL_NAMES+'
)
) PIVT
ORDER BY id_number'
EXEC (@SQL);
答案 1 :(得分:0)
这使用for xml
但是应该以相同的方式工作
DECLARE @exams nvarchar(max), @sql nvarchar(max)
SET @exams = SELECT STUFF(SELECT ',', + QUOTENAME(t.itemname)
FROM (
SELECT DISTINCT gi.itemname
FROM mdl_grade_items gi
WHERE gi.itemname IS NOT NULL AND gi.courseid = 123
ORDER BY gi.itemname
) t
FOR XML PATH(''), 0, 1, '')
SET @sql = N'
SELECT *
FROM
(SELECT
u.firstname AS name,
u.lastname AS last_name,
u.idnumber AS id_number,
gi.itemname AS exam_name,
CAST(gg.finalgrade / gi.grademax * 100 AS integer) AS grade
FROM
mdl_grade_grades gg
INNER JOIN
mdl_grade_items gi ON gg.itemid = gi.id
INNER JOIN
mdl_course c ON gi.courseid = c.id
INNER JOIN
mdl_user u ON gg.userid = u.id
WHERE
(gi.itemname IS NOT NULL)
AND (gi.courseid = 123)) SOURCE
PIVOT
(MAX(grade)
FOR exam_name IN (' + @exams + ')
) PIVT
ORDER BY
id_number
'
EXEC sp_executesql @sql