书接上回(1-25)

经典50题(26-50)

查询每门课被选修的学生数

1
2
3
4
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计数

查询出只有两门课程的全部学生的学号和姓名

1
2
3
4
5
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计数

查询男女生人数

1
2
3
SELECT s_sex,COUNT(DISTINCT s_id) AS '人数'
FROM Student
GROUP BY s_sex

查询名字中含有 风 字的学生信息

1
2
3
SELECT * 
FROM Student
WHERE s_name LIKE '%风%'

查询同名同性的学生名单,并统计同名人数

1
2
3
4
5
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;
  1. GROUP BY s.s_name, s.s_sex:根据学生的姓名和性别进行分组,这样具有相同姓名和性别的学生会被分为一组。
  2. HAVING COUNT(*) > 1HAVING 子句用于筛选分组后的结果。这里它用来找出那些出现次数大于1的组,即同名同性的学生。

查询 1990 年出生的学生信息

1
2
3
SELECT *
FROM Student
WHERE YEAR(DATE(s_birth))=1990

DATE() 可以将varchar转成日期型
YEAR() 函数返回一个指定日期or时间的年份值,范围为1000到9999,如果日期为零,YEAR()函数返回0

查询每门课程的平均成绩,结果按平均成绩降序排列;平均成绩相同时,按课程编号 c_id 升序排列

1
2
3
4
5
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 的所有学生的学号、姓名和平均成绩

1
2
3
4
5
6
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 的学生姓名和分数

1
2
3
4
5
6
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
##这题连接三张表也可以

查询所有学生的课程及分数情况

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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 分以上的姓名、课程名称和分数

1
2
3
4
5
6
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

查询不及格的课程

1
2
3
4
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 的学生的学号和姓名

1
2
3
4
5
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

每门课程的学生人数

1
2
3
4
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

查询选修“张三”老师所授课程的学生中,成绩最高的学生信息及其成绩

1
2
3
4
5
6
7
8
9
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;

查询不同课程成绩相同的学生的学生编号、课程编号、学生成绩

1
2
3
4
5
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;
  1. 将成绩表自身进行连接(自连接),连接条件是两个不同的成绩记录具有相同的分数,但课程编号不同。
  2. HAVING 子句用于筛选分组后的结果,这里它用来找出那些在多个不同课程中具有相同成绩的学生记录。

查询每门功课成绩最好的前两名

1
2
3
4
5
6
7
8
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 人的课程才统计)。要求输出课程号和选修人数,查询结果按人数降序排列, 若人数相同,按课程号升序排列

1
2
3
4
SELECT c_id,COUNT(DISTINCT s_id) AS NUMS
FROM Score
GROUP BY c_id
ORDER BY NUMS DESC,c_id ASC

检索至少选修两门课程的学生学号

1
2
3
4
SELECT s_id
FROM Score
GROUP BY s_id
HAVING COUNT(DISTINCT c_id)>=2S

查询选修了全部课程的学生信息

1
2
3
4
5
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

1
2
3
4
5
6
7
8
9
10
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

查询本周过生日的学生

1
2
3
SELECT s.*
FROM student s
WHERE WEEK(DATE(s.s_birth))=WEEK(NOW())

查询下周过生日的学生

1
2
3
SELECT s.*
FROM student s
WHERE WEEK(DATE(s.s_birth))=WEEK(NOW())+1

查询本月过生的同学

1
2
3
SELECT s.*
FROM student s
WHERE MONTH(DATE(s.s_birth))=MONTH(NOW())

查询下月过生日的学生

1
2
3
SELECT s.*
FROM student s
WHERE MONTH(DATE(s.s_birth))=MONTH(NOW())+1