SQL50题解题思路 Q1-5
注意事项
建表语句及题目参考于超经典SQL练习题,做完这些你的SQL就过关了 - flycat296的博客 - CSDN博客,不同来源的题目和建表语句会有细微差别。
本解题思路仅代表个人思路,并非一定正确,仅供参考。建议观看答案前自己建表做一遍。
1. 查询" 01 "课程比" 02 "课程成绩高的学生的信息及课程分数
思路
题目要求可以分成两部分,查询的信息为学生的信息及课程分数,条件是" 01 "课程比" 02 "课程成绩高。
学生信息和课程分数在两个不同的表,所以需要用join把两个表连接起来。但是直接连接的话每个学生会有多条记录对应不同的课程,课程成绩互相比较会比较麻烦,而观察数据库可知课程一共只有三门。所以可以考虑把每一门课程的成绩分别连接到学生信息表上。用
select S#,score score1 from SC where C# = '01'
选择某一门课程的成绩并给成绩整一个别名,然后分别连接到Student表上。考虑到有些学生没有选修某些课程所以用left join确保数据完整。连接之后再比较" 01 "课程和" 02 "课程成绩就比较简单了,直接一句where搞定。
代码
SELECT s.*, c1.score1, c2.score2, c3.score3
FROM Student s
LEFT JOIN(SELECT S#, score score1 FROM SC WHERE C# = '01')c1 ON s.S#=c1.S#
LEFT JOIN(SELECT S#, score score2 FROM SC WHERE C# = '02')c2 ON s.S#=c2.S#
LEFT JOIN(SELECT S#, score score3 FROM SC WHERE C# = '03')c3 ON s.S#=c3.S#
WHERE c1.score1>c2.score2
/*
如果考虑02课程没有成绩可以将最后一句改为
where c1.score1>c2.score2 or (c2.score2 is null and c1.score1 is not null)
*/
1.1 查询同时存在" 01 "课程和" 02 "课程的情况
按上述步骤做完1后1.1-1.3就比较简单了改一下where里的条件就搞定。
代码
SELECT s.*, c1.score1, c2.score2, c3.score3
FROM Student s
LEFT JOIN(SELECT S#, score score1 FROM SC WHERE C# = '01')c1 ON s.S#=c1.S#
LEFT JOIN(SELECT S#, score score2 FROM SC WHERE C# = '02')c2 ON s.S#=c2.S#
LEFT JOIN(SELECT S#, score score3 FROM SC WHERE C# = '03')c3 ON s.S#=c3.S#
WHERE c2.score2 IS NOT NULL AND c1.score1 IS NOT NULL
1.2 查询存在" 01 "课程但可能不存在" 02 "课程的情况(不存在时显示为 null )
代码
SELECT s.*, c1.score1, c2.score2, c3.score3
FROM Student s
LEFT JOIN(SELECT S#, score score1 FROM SC WHERE C# = '01')c1 ON s.S#=c1.S#
LEFT JOIN(SELECT S#, score score2 FROM SC WHERE C# = '02')c2 ON s.S#=c2.S#
LEFT JOIN(SELECT S#, score score3 FROM SC WHERE C# = '03')c3 ON s.S#=c3.S#
WHERE c1.score1 IS NOT NULL
1.3 查询不存在" 01 "课程但存在" 02 "课程的情况
代码
SELECT s.*, c1.score1, c2.score2, c3.score3
FROM Student s
LEFT JOIN(SELECT S#, score score1 FROM SC WHERE C# = '01')c1 ON s.S#=c1.S#
LEFT JOIN(SELECT S#, score score2 FROM SC WHERE C# = '02')c2 ON s.S#=c2.S#
LEFT JOIN(SELECT S#, score score3 FROM SC WHERE C# = '03')c3 ON s.S#=c3.S#
WHERE c2.score2 IS NOT NULL AND c1.score1 IS NULL
2. 查询平均成绩大于等于 60 分的同学的学生编号和学生姓名和平均成绩
思路
平均成绩可以用avg()函数求得,因为是每个同学的平均成绩,所以用group by按学生编号进行分组。
因为需要查询学生姓名,所以求得平均成绩后需要连接学生信息表。在where处判断平均成绩是否大于等于60。
代码
SELECT s.Sname, c.*
FROM
(
SELECT S#, AVG(score) avg_score
FROM SC
GROUP BY S#
)c
JOIN Student s ON c.S#=s.S#
WHERE c.avg_score >= 60
3. 查询在 SC 表存在成绩的学生信息
思路
在该数据库中存在成绩就相当于存在数据(SC表中没有null),所以直接判断学生编号是否在SC表中出现过即可。
要求输出的是学生信息,所以输出Student表。使用where语句判断S#(学生编号)是否在SC中出现过。只用select不加distinct也可以得到一样的答案,但是不加distinct在数据量巨大的时候可能会导致运行时间显著增长,所以建议还是加上,养成良好的代码习惯Orz。
代码
SELECT *
FROM Student s
WHERE S# IN(SELECT DISTINCT S# FROM SC)
4. 查询所有同学的学生编号、学生姓名、选课总数、所有课程的总成绩(没成绩的显示为 null )
思路
需要查询选课数和总成绩,所以需要分组,然后又需要查询姓名,所以要和Student表连接。
这里有两种方法,可以先对SC表进行分组后连接Student,也可以先连接Student后分组。
先对SC表进行分组后连接Student会导致一些课程总数显示为null(显示为0更符合题意)。可以用is null()函数将null值置换为0。
先连接后分组则可能会报错(某些sql版本),因为学生姓名之类的信息既不是group by的key,也没有用聚合函数。一种解决方案是把姓名等也做为key。
代码
-- 方法1
SELECT s.*, ISNULL(c.count_courses,0) count_courses, c.sum_score
FROM Student s
LEFT JOIN
(
SELECT S#, COUNT(C#) count_courses, SUM(score) sum_score
FROM SC
GROUP BY S#
)c ON s.S# = c.S#
-- 方法2
SELECT s.*, COUNT(C#) count_courses, SUM(score) sum_score
FROM Student s
LEFT JOIN SC c
ON s.S#=c.S#
GROUP BY s.S#,s.Sname,s.Sage,s.Ssex
4.1 查有成绩的学生信息
思路
似乎和Q3重复了,所以就当这里的信息是指Q4提到的信息。在Q4的基础上不用left join,改成inner join(inner可以省略)就可以只保留有成绩的学生了。
代码
SELECT s.*, count_courses, sum_score
FROM Student s
JOIN
(
SELECT S#, COUNT(C#) count_courses, SUM(score) sum_score
FROM SC
GROUP BY S#
)c ON s.S# = c.S#
5. 查询「李」姓老师的数量
思路
老师相关的数据保存在Teacher表中,所以对该表进行操作即可。
查询的是数量所以用count()函数,条件为李姓,即名字字段第一个字符为李,用%通配符'李%'即可。
需要注意的是数据库中的字段值是unicode编码的(类型是nvarchar),所以需要加上N即N'李%'
代码
SELECT COUNT(T#) cnt_李
FROM Teacher
WHERE Tname LIKE N'李%'