使用SQL Server 2016数据库,我使用以下代码:
SELECT * FROM (
SELECT
u.firstname AS 'first name',
u.lastname AS 'last name',
gi.idnumber AS 'examcode',
gg.finalgrade AS 'grade'
FROM mdl_grade_grades gg
INNER JOIN mdl_grade_items gi ON gg.itemid = gi.id
INNER JOIN mdl_user u ON gg.userid = u.id
WHERE gi.idnumber IN ('148','414','413','228','359','379','398','104','351','436','434','384','385','377','280','395')
AND gg.userid = '62750'
) SOURCE
PIVOT (
MAX(grade)
FOR examcode IN ([148],[414],[413],[228],[359],[379],[398],[104],[351],[436],[434],[384],[385],[377],[280],[395])
) PIVT
ORDER BY 'last name', 'first name'
生成各种gi.examcodes的分数的枢轴列表。 如果没有特定gi.examcode的记录(行),则SQL Server数据库将返回NULL,如下所示:
first name last name 148 413 228 359 379 398 104 351 436 434 384 385 377 280 395
John Brown 94 96 97 NULL NULL NULL 100 NULL NULL 94 86 83 85 93 NULL
当写入html页面时,该表将在有NULL的地方显示空值。我该如何用通用值替换返回的NULL,如下所示:
first name last name 148 413 228 359 379 398 104 351 436 434 384 385 377 280 395
John Brown 94 96 97 None None None 100 None None 94 86 83 85 93 None
答案 0 :(得分:2)
最好在表示层处理此类表示问题。但是,如果不能,则必须更改查询,因为PIVOT
不直接支持表达式。一些选项:
选项1-嵌套PIVOT
:
SELECT [first name], [last name],
[148] = COALESCE([148],'None'), [414] = COALESCE([414],'None'),
[413] = COALESCE([413],'None'), [228] = COALESCE([228],'None'),
[359] = COALESCE([359],'None'), [379] = COALESCE([379],'None'),
[398] = COALESCE([398],'None'), [104] = COALESCE([104],'None'),
[351] = COALESCE([351],'None'), [436] = COALESCE([436],'None'),
[434] = COALESCE([434],'None'), [384] = COALESCE([384],'None'),
[385] = COALESCE([385],'None'), [377] = COALESCE([377],'None'),
[280] = COALESCE([280],'None'), [395] = COALESCE([395],'None')
FROM
(
SELECT * FROM
(
SELECT
u.firstname AS [first name],
u.lastname AS [last name],
gi.idnumber AS [examcode],
CONVERT(varchar(11), gg.finalgrade) AS grade -- if grade is actually numeric
FROM dbo.mdl_grade_grades gg
INNER JOIN dbo.mdl_grade_items gi ON gg.itemid = gi.id
INNER JOIN dbo.mdl_user u ON gg.userid = u.id
WHERE gi.idnumber IN ('148','414','413','228','359','379','398','104',
'351','436','434','384','385','377','280','395')
AND gg.userid = '62750'
) SOURCE
PIVOT (
MAX(grade)
FOR examcode IN ([148],[414],[413],[228],[359],[379],[398],[104],
[351],[436],[434],[384],[385],[377],[280],[395])
) PIVT
) x
ORDER BY [last name], [first name];
选项2-MAX(CASE
:
SELECT [first name] = firstname, [last name] = lastname,
[148] = COALESCE(MAX(CASE idnumber WHEN '148' THEN grade END), 'None'),
[414] = COALESCE(MAX(CASE idnumber WHEN '414' THEN grade END), 'None'),
[413] = COALESCE(MAX(CASE idnumber WHEN '413' THEN grade END), 'None'),
[228] = COALESCE(MAX(CASE idnumber WHEN '228' THEN grade END), 'None'),
[359] = COALESCE(MAX(CASE idnumber WHEN '359' THEN grade END), 'None'),
[379] = COALESCE(MAX(CASE idnumber WHEN '379' THEN grade END), 'None'),
[398] = COALESCE(MAX(CASE idnumber WHEN '398' THEN grade END), 'None'),
[104] = COALESCE(MAX(CASE idnumber WHEN '104' THEN grade END), 'None'),
[351] = COALESCE(MAX(CASE idnumber WHEN '351' THEN grade END), 'None'),
[436] = COALESCE(MAX(CASE idnumber WHEN '436' THEN grade END), 'None'),
[434] = COALESCE(MAX(CASE idnumber WHEN '434' THEN grade END), 'None'),
[384] = COALESCE(MAX(CASE idnumber WHEN '384' THEN grade END), 'None'),
[385] = COALESCE(MAX(CASE idnumber WHEN '385' THEN grade END), 'None'),
[377] = COALESCE(MAX(CASE idnumber WHEN '377' THEN grade END), 'None'),
[280] = COALESCE(MAX(CASE idnumber WHEN '280' THEN grade END), 'None'),
[395] = COALESCE(MAX(CASE idnumber WHEN '395' THEN grade END), 'None')
FROM
(
SELECT u.firstname, u.lastname, gi.idnumber,
grade = CONVERT(varchar(11), gg.finalgrade)
FROM dbo.mdl_grade_grades AS gg
INNER JOIN dbo.mdl_grade_items AS gi
ON gg.itemid = gi.id
INNER JOIN dbo.mdl_user AS u
ON gg.userid = u.id
WHERE gi.idnumber IN ('148','414','413','228','359','379','398','104',
'351','436','434','384','385','377','280','395')
AND gg.userid = '62750'
) AS x
GROUP BY lastname, firstname
ORDER BY lastname, firstname;
选项#3-动态SQL-在添加/删除课程方面更加灵活,仅指定一次课程列表,并且根据读者的不同,阅读起来可能更容易/更难。
DECLARE @userid varchar(11) = '62750', @sql nvarchar(max) = N'SELECT
[first name] = firstname,
[last name] = lastname';
CREATE TABLE #g(i int IDENTITY(1,1), id varchar(4));
INSERT #g VALUES ('148'),('414'),('413'),('228'),('359'),('379'),('398'),('104'),
('351'),('436'),('434'),('384'),('385'),('377'),('280'),('395');
SELECT @sql += N',
' + QUOTENAME(id) + N' = COALESCE(MAX(CASE i WHEN '''
+ id + ''' THEN grade END),''None'')'
FROM #g ORDER BY i;
SET @sql += N'
FROM
(
SELECT u.firstname, u.lastname, gi.idnumber AS i,
grade = CONVERT(varchar(11), gg.finalgrade)
FROM dbo.mdl_grade_grades AS gg
INNER JOIN dbo.mdl_grade_items AS gi
ON gg.itemid = gi.id
INNER JOIN dbo.mdl_user AS u
ON gg.userid = u.id
INNER JOIN #g AS g
ON g.id = gi.idnumber
WHERE gg.userid = @userid
) AS x
GROUP BY lastname, firstname
ORDER BY lastname, firstname;';
EXEC sys.sp_executesql @sql, N'@userid varchar(11)', @userid;
DROP TABLE #g;
有很多方法可以做到这一点,但是它们都将是丑陋的或不直观的(有时两者都是)。这是因为T-SQL并不是用来美化演示文稿的-这就是HTML,CSS,JavaScript和其他客户端技术的目的。另外,您应该将数字存储为数字并将其视为数字。还有always use semi-colons,always use the schema prefix,并且不要使用AS 'last name'
-相反,使用AS [last name]
更安全。
答案 1 :(得分:1)
而不是在外部选择中使用splat,而是对每个字段进行寻址并处理空值。
SELECT
[first name]
, [last name]
, [examcode]
,isnull([148], 0) as [148]
,isnull([414], 0) as [414]
,isnull([413], 0) as [413]
,isnull([228], 0) as [228]
,isnull([359], 0) as [359]
,isnull([379], 0) as [379]
,isnull([398], 0) as [398]
,isnull([104], 0) as [104]
,isnull([351], 0) as [351]
,isnull([436], 0) as [436]
,isnull([434], 0) as [434]
,isnull([384], 0) as [384]
,isnull([385], 0) as [385]
,isnull([377], 0) as [377]
,isnull([280], 0) as [280]
,isnull([395], 0) as [395]
FROM (
SELECT
u.firstname AS 'first name',
u.lastname AS 'last name',
gi.idnumber AS 'examcode',
gg.finalgrade AS 'grade'
FROM mdl_grade_grades gg
INNER JOIN mdl_grade_items gi ON gg.itemid = gi.id
INNER JOIN mdl_user u ON gg.userid = u.id
WHERE gi.idnumber IN ('148','414','413','228','359','379','398','104','351','436','434','384','385','377','280','395')
AND gg.userid = '62750'
) SOURCE
PIVOT (
MAX(grade)
FOR examcode IN ([148],[414],[413],[228],[359],[379],[398],[104],[351],[436],[434],[384],[385],[377],[280],[395])
) PIVT
ORDER BY 'last name', 'first name'
答案 2 :(得分:1)
另一种选择是通过CROSS JOIN创建可能组合的子集,然后在PIVOT中执行UNION ALL
示例
;with cte0 as (
SELECT
u.firstname AS [first name],
u.lastname AS [last name],
gi.idnumber AS [examcode],
convert(varchar(50),gg.finalgrade) AS [grade]
FROM mdl_grade_grades gg
INNER JOIN mdl_grade_items gi ON gg.itemid = gi.id
INNER JOIN mdl_user u ON gg.userid = u.id
WHERE gi.idnumber IN ('148','414','413','228','359','379','398','104','351','436','434','384','385','377','280','395')
AND gg.userid = '62750'
),cte1 as (
Select [first name],[last name],examcode,grade
From (Select Distinct [first name],[last name] from cte0 ) A
Cross Join (Select Distinct examcode,grade='None' from cte0) B
)
Select *
From (
Select * from cte0
Union All
Select * from cte1
) src
Pivot (
max(grade)
for examcode IN ([148],[414],[413],[228],[359],[379],[398],[104],[351],[436],[434],[384],[385],[377],[280],[395])
) pvt
ORDER BY [last name], [first name]
答案 3 :(得分:0)
您可以将当前查询设为CTE或派生表,然后使用ISNULL()从中进行选择。