所有笔记、生活分享首发于个人博客
想要获得最佳的阅读体验(无广告且清爽),请访问本篇笔记
书接上回(1-25)
经典50题(26-50)
查询每门课被选修的学生数
sql
SELECT c.c_name,COUNT(DISTINCT sc.s_id) AS s_num
FROM Score sc
JOIN Course c ON sc.c_id=c.c_id
GROUP BY c.c_name
成绩表按科目对s_id计数
查询出只有两门课程的全部学生的学号和姓名
sql
SELECT s.s_id,s.s_name
FROM Score sc
JOIN Student s ON sc.s_id=s.s_id
GROUP BY s.s_id
HAVING COUNT(DISTINCT sc.c_id)=2
成绩表按学生对c_id计数
查询男女生人数
sql
SELECT s_sex,COUNT(DISTINCT s_id) AS '人数'
FROM Student
GROUP BY s_sex
查询名字中含有 风 字的学生信息
sql
SELECT *
FROM Student
WHERE s_name LIKE '%风%'
查询同名同性的学生名单,并统计同名人数
SQL
SELECT s.s_name, s.s_sex, COUNT(*) AS same_name_sex_count
FROM Student AS s
GROUP BY s.s_name, s.s_sex
HAVING COUNT(*) > 1
ORDER BY s.s_name, same_name_sex_count DESC;
GROUP BY s.s_name, s.s_sex
:根据学生的姓名和性别进行分组,这样具有相同姓名和性别的学生会被分为一组。HAVING COUNT(*) > 1
:HAVING
子句用于筛选分组后的结果。这里它用来找出那些出现次数大于1的组,即同名同性的学生。
查询 1990 年出生的学生信息
sql
SELECT *
FROM Student
WHERE YEAR(DATE(s_birth))=1990
DATE() 可以将varchar转成日期型
YEAR() 函数返回一个指定日期or时间的年份值,范围为1000到9999,如果日期为零,YEAR()函数返回0
查询每门课程的平均成绩,结果按平均成绩降序排列;平均成绩相同时,按课程编号 c_id 升序排列
SQL
SELECT c.c_name,ROUND(AVG(sc.s_score),2) AS '平均分'
FROM Score sc
JOIN Course c ON sc.c_id=c.c_id
GROUP BY c.c_id
ORDER BY AVG(sc.s_score) DESC,c.c_id ASC
查询平均成绩大于等于 85 的所有学生的学号、姓名和平均成绩
SQL
SELECT s.s_id,s.s_name,ROUND(AVG(sc.s_score),2) AS '平均成绩'
FROM Score sc
JOIN Student s ON sc.s_id=s.s_id
GROUP BY s.s_id
HAVING AVG(sc.s_score)>=85
ORDER BY AVG(sc.s_score) DESC
查询课程名称为数学,且分数低于 60 的学生姓名和分数
sql
SELECT s.s_name,sc.s_score
FROM Score sc
JOIN Student s ON sc.s_id=s.s_id
WHERE c_id=(SELECT c_id FROM Course WHERE c_name='数学')
AND s_score<60
##这题连接三张表也可以
查询所有学生的课程及分数情况
sql
SELECT
s.s_name,
SUM(CASE WHEN c.c_name = '语文' THEN sc.s_score ELSE 0 END) AS 语文,
SUM(CASE WHEN c.c_name = '数学' THEN sc.s_score ELSE 0 END) AS 数学,
SUM(CASE WHEN c.c_name = '英语' THEN sc.s_score ELSE 0 END) AS 英语,
SUM(sc.s_score) AS 总分
FROM
Student s
LEFT JOIN
Score sc ON s.s_id = sc.s_id
LEFT JOIN
Course c ON sc.c_id = c.c_id
GROUP BY
s.s_name, s.s_id; -- 增加 s.s_id 以确保正确分组
查询任何一门课程成绩在 70 分以上的姓名、课程名称和分数
sql
SELECT s.s_name,c.c_name,sc.s_score
FROM Score sc
JOIN Student s ON sc.s_id=s.s_id
JOIN Course c ON sc.s_id=c.c_id
WHERE s_score>70
查询不及格的课程
sql
SELECT sc.c_id,c.c_name,sc.s_score
FROM Score sc
JOIN Course c ON sc.c_id=c.c_id
WHERE sc.s_score<60
查询课程编号为 01 且课程成绩大于等于 80 的学生的学号和姓名
sql
SELECT s.s_id,s.s_name
FROM Score sc
LEFT JOIN Student s ON sc.s_id=s.s_id
WHERE c_id='01'
AND s_score>=80
每门课程的学生人数
sql
SELECT c.c_name,count(DISTINCT sc.s_id) AS '人数'
FROM Score sc
JOIN Course c ON sc.c_id=c.c_id
GROUP BY c.c_name
查询选修"张三"老师所授课程的学生中,成绩最高的学生信息及其成绩
sql
SELECT s.*, MAX(sc.s_score) AS 最高成绩
FROM Student AS s
JOIN Score AS sc ON s.s_id = sc.s_id
JOIN Course AS c ON sc.c_id = c.c_id
JOIN Teacher AS t ON c.t_id = t.t_id
WHERE t.t_name = '张三'
GROUP BY s.s_id, s.s_name -- 避免同名
ORDER BY 最高成绩 DESC
LIMIT 1;
查询不同课程成绩相同的学生的学生编号、课程编号、学生成绩
SQL
SELECT sc1.s_id,sc1.c_id,sc1.s_score
FROM Score AS sc1
JOIN Score AS sc2 ON sc1.s_score = sc2.s_score AND sc1.c_id <> sc2.c_id
GROUP BY sc1.s_id, sc1.c_id, sc1.s_score
HAVING COUNT(DISTINCT sc2.c_id) > 1;
- 将成绩表自身进行连接(自连接),连接条件是两个不同的成绩记录具有相同的分数,但课程编号不同。
HAVING
子句用于筛选分组后的结果,这里它用来找出那些在多个不同课程中具有相同成绩的学生记录。
查询每门功课成绩最好的前两名
sql
SELECT r.*
FROM(
SELECT c_name,s_name,s_score,
ROW_NUMBER()OVER(PARTITION BY c_name ORDER BY s_score DESC) as rank_num
FROM Score sc
JOIN Course c ON sc.c_id=c.c_id
JOIN student s ON sc.s_id=s.s_id) r
WHERE r.rank_num<=2
窗口函数
ROW_NUMBER()
为每个课程 (PARTITION BY c_name
) 的成绩分配一个唯一的序号,按分数降序排列 (ORDER BY s_score DESC
)。通过相应的 ID 关联这三个表,以获取完整的课程和学生信息以及他们的分数。
最后通过where筛选出每门课程成绩排名前两名的学生。
统计每门课程的学生选修人数(超过 5 人的课程才统计)。要求输出课程号和选修人数,查询结果按人数降序排列, 若人数相同,按课程号升序排列
SQL
SELECT c_id,COUNT(DISTINCT s_id) AS NUMS
FROM Score
GROUP BY c_id
ORDER BY NUMS DESC,c_id ASC
检索至少选修两门课程的学生学号
SQL
SELECT s_id
FROM Score
GROUP BY s_id
HAVING COUNT(DISTINCT c_id)>=2S
查询选修了全部课程的学生信息
sql
SELECT s.*
FROM student s
JOIN score sc ON s.s_id = sc.s_id
GROUP BY s.s_id
HAVING COUNT(DISTINCT c_id)=(SELECT COUNT(*)FROM course)
查询各学生的年龄:按照出生日期来算,当前月日 < 出生年月的月日则,年龄减 1
sql
SELECT s.*,
CASE
WHEN MONTH(NOW())<MONTH(DATE(s_birth)) THEN
YEAR(NOW())-YEAR(DATE(s_birth))-1
WHEN MONTH(NOW())=MONTH(DATE(s_birth)) AND DAY(NOW())<DAY(DATE(s_birth)) THEN
YEAR(NOW())-YEAR(DATE(s_birth))-1
ELSE
YEAR(NOW())-YEAR(DATE(s_birth))
END AS age
FROM Student s
查询本周过生日的学生
sql
SELECT s.*
FROM student s
WHERE WEEK(DATE(s.s_birth))=WEEK(NOW())
查询下周过生日的学生
sql
SELECT s.*
FROM student s
WHERE WEEK(DATE(s.s_birth))=WEEK(NOW())+1
查询本月过生的同学
sql
SELECT s.*
FROM student s
WHERE MONTH(DATE(s.s_birth))=MONTH(NOW())
查询下月过生日的学生
sql
SELECT s.*
FROM student s
WHERE MONTH(DATE(s.s_birth))=MONTH(NOW())+1