昨晚在CSDN论坛上看到有某个人问了类似这样的一个问题,现有三个数据表,分别是学生表,课程表,成绩表。它们的结构与样例数据如下:
学生表:
学生Id 姓名
1 张三
2 李四
3 王五
课程表:
课程Id 课程名
1 语文
2 化学
3 外语
4 物理
成绩表:
学生Id 课程Id 成绩
1 1 60
1 2 70
1 3 65
1 4 90
2 1 80
2 2 65
2 3 85
2 4 80
3 1 50
3 2 75
3 3 85
3 4 60
现要求在一行中输出每个学生的所有课程的成绩单,显示样例格式如下:
姓名 语文 化学 外语 物理
张三 60 70 65 90
李四 80 65 85 80
王五 50 75 85 60
当大家看到这样的题目时会优先考虑到的是怎样的一条SQL语句呢?嵌套Select?对,在将行转换为列时,也许这种方法是最优先考虑到(或者你是高手,所以不是优先考虑到这个而是其它
),所以我最开始也写出了下面这条语句:
SELECT B.姓名,
(SELECT 成绩 FROM 成绩表 INNER JOIN 课程 ON 成绩表.课程ID=课程.课程ID WHERE 成绩表.学生ID=B.学生ID AND 课程.课程名='语文' ) AS 语文,
(SELECT 成绩 FROM 成绩表 INNER JOIN 课程 ON 成绩表.课程ID=课程.课程ID WHERE 成绩表.学生ID=B.学生ID AND 课程.课程名='化学' ) AS 化学,
(SELECT 成绩 FROM 成绩表 INNER JOIN 课程 ON 成绩表.课程ID=课程.课程ID WHERE 成绩表.学生ID=B.学生ID AND 课程.课程名='外语' ) AS 外语,
(SELECT 成绩 FROM 成绩表 INNER JOIN 课程 ON 成绩表.课程ID=课程.课程ID WHERE 成绩表.学生ID=B.学生ID AND 课程.课程名='物理' ) AS 物理
FROM 学生 B

这样我们的目的是达到了,但后来我又想了一下,因为我们要的数据其实都在
成绩表里,只不过现有的是用行来存放,那我们怎么将它转换为列显示呢?嗯,这也许就要搬出聚合函数加Case条件来处理了!最终的SQL语句如下:
SELECT 姓名,
MAX(CASE 课程名 WHEN '语文' THEN 成绩 ELSE 0 END) AS 语文,
MAX(CASE 课程名 WHEN '化学' THEN 成绩 ELSE 0 END) AS 化学,
MAX(CASE 课程名 WHEN '外语' THEN 成绩 ELSE 0 END) AS 外语,
MAX(CASE 课程名 WHEN '物理' THEN 成绩 ELSE 0 END) AS 物理
FROM (SELECT B.姓名,C.课程名,D.成绩 FROM 成绩表 D
INNER JOIN 学生 B ON B.学生ID=D.学生ID
INNER JOIN 课程 C ON C.课程ID=D.课程ID) AS TMP GROUP BY 姓名

运行后,也是可以得到正确的数据,下面给出测试代码,大家可以直接在SQL查询分析器里运行
CREATE TABLE 学生 (学生ID INT, 姓名 VARCHAR(20))
CREATE TABLE 课程 (课程ID INT, 课程名 VARCHAR(20))
CREATE TABLE 成绩表 (学生ID INT, 课程ID INT, 成绩 INT)

INSERT INTO 学生
SELECT 1,'张三' UNION ALL
SELECT 2,'李四' UNION ALL
SELECT 3,'王五'

INSERT INTO 课程
SELECT 1,'语文' UNION ALL
SELECT 2,'化学' UNION ALL
SELECT 3,'外语' UNION ALL
SELECT 4,'物理'

INSERT INTO 成绩表
SELECT 1,1,60 UNION ALL
SELECT 1,2,70 UNION ALL
SELECT 1,3,65 UNION ALL
SELECT 1,4,90 UNION ALL
SELECT 2,1,80 UNION ALL
SELECT 2,2,65 UNION ALL
SELECT 2,3,85 UNION ALL
SELECT 2,4,80 UNION ALL
SELECT 3,1,50 UNION ALL
SELECT 3,2,75 UNION ALL
SELECT 3,3,85 UNION ALL
SELECT 3,4,60

--方法一
SELECT B.姓名,
(SELECT 成绩 FROM 成绩表 INNER JOIN 课程 ON 成绩表.课程ID=课程.课程ID WHERE 成绩表.学生ID=B.学生ID AND 课程.课程名='语文' ) AS 语文,
(SELECT 成绩 FROM 成绩表 INNER JOIN 课程 ON 成绩表.课程ID=课程.课程ID WHERE 成绩表.学生ID=B.学生ID AND 课程.课程名='化学' ) AS 化学,
(SELECT 成绩 FROM 成绩表 INNER JOIN 课程 ON 成绩表.课程ID=课程.课程ID WHERE 成绩表.学生ID=B.学生ID AND 课程.课程名='外语' ) AS 外语,
(SELECT 成绩 FROM 成绩表 INNER JOIN 课程 ON 成绩表.课程ID=课程.课程ID WHERE 成绩表.学生ID=B.学生ID AND 课程.课程名='物理' ) AS 物理
FROM 学生 B

--方法二
SELECT 姓名,
MAX(CASE 课程名 WHEN '语文' THEN 成绩 ELSE 0 END) AS 语文,
MAX(CASE 课程名 WHEN '化学' THEN 成绩 ELSE 0 END) AS 化学,
MAX(CASE 课程名 WHEN '外语' THEN 成绩 ELSE 0 END) AS 外语,
MAX(CASE 课程名 WHEN '物理' THEN 成绩 ELSE 0 END) AS 物理
FROM (SELECT B.姓名,C.课程名,D.成绩 FROM 成绩表 D
INNER JOIN 学生 B ON B.学生ID=D.学生ID
INNER JOIN 课程 C ON C.课程ID=D.课程ID) AS TMP GROUP BY 姓名


DROP TABLE 学生
DROP TABLE 课程
DROP TABLE 成绩表PS:用嵌套SELECT与用聚合函数加Case两者的效率如何,我没有测试,各位有兴趣的可测试一下
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义