SQL汇总
- 1. SQL执行顺序
- 2. 开窗函数
- 3. 经典SQL题
- 3.0 数据准备
- 3.1 ☆ 查询‘01’课程比‘02’课程成绩高的学生
- 3.2 查询平均成绩大于等于60分的同学的学生编号和学生姓名和平均成绩
- 3.3 查询在SC表存在成绩的学生信息
- 3.4 查询所有同学的学生编号、学生姓名、选课总数、所有课程的总成绩(没成绩的显示null)
- 3.5 查询【李】姓老师的数量
- 3.6 查询学过【张三】老师授课的同学的信息
- 3.7 查询没有学全所有课程的同学的信息
- 3.8 查询至少有一门课与学号为‘01’的同学所学相同的同学的信息
- 3.9 ☆ 查询和‘01’号同学学习的课程完全相同的其他同学的信息
- 3.10 ☆ 查询没学过【张三】老师讲授的任意门课程的学生姓名
- 3.11 查询两门及以上不合格课程的同学的学号,姓名及其平均成绩
- 3.12 检索‘01’课程分数小于60,按分数降序排列的学生信息
- 3.13 按平均成绩的高到低显示所有学生的所有课程的成绩以及平均成绩
- 3.14 ☆ 查询各科成绩最高分、最低分和平均分
- 3.15 ☆ 按各科成绩进行排序,并显示排名,Score重复时也继续排名
- 3.16 ☆ 查询学生的总成绩,并进行排名,总分重复时保留名次空缺
- 3.17 ☆ 统计各科成绩各分数段人数
- 3.18 ☆ 查询各科成绩前三名的记录
- 3.19 查询每一门课程被选修的学生数
- 3.20 查询出只选修两门课程的学生学号和姓名
- 3.21 查询男生、女生人数
- 3.22 查询名字中含有【风】字的学生信息
- 3.23 查询同名同性学生名单,并统计同名同性人数
- 3.24 查询1990年出生的学生名单
- 3.25 查询每门课程的平均成绩,结果按平均成绩降序排列,平均成绩相同时,按课程编号升序排列
- 3.26 查询平均成绩大于等于 85 的所有学生的学号、姓名和平均成绩
- 3.27 查询课程名称【数学】,且分数低于60的学生姓名和分数
- 3.28 询所有学生的课程及分数情况(存在学生没成绩,没选课的情况)
- 3.29 查询任何一门课程成绩在70分以上的姓名、课程名称和分数
- 3.30 查询存在不及格的课程
- 3.31 查询课程编号为01且课程成绩在80分以上的学生的学号和姓名
- 3.32 求每门课程的学生人数
- 3.33 ☆ 假设成绩不重复,查询选修【张三】老师所授课程的学生中,成绩最高的学生信息及其成绩
- 3.34 ☆ 假设成绩有重复的情况下,查询选修【张三】老师所授课程的学生中,成绩最高的学生信息及其成绩
- 3.35 查询不同课程成绩相同的学生的学生编号、课程编号、学生成绩
- 3.36 ☆ 查询每门科目成绩最好的前两名
- 3.37 统计每门课程的学生选修人数(超过5人的课程才统计)
- 3.38 检索至少选修两门课程的学生学号
- 3.39 查询选修了全部课程的学生信息
- 3.40 查询各学生的年龄,只按年份来算
- 3.41 ☆ 查询各学生的年龄,按出生日期来算,当前月日 < 出生年月的月日则,年龄减一
- 3.42 查询本周过生日的学生
- 3.43 查询下周过生日的学生
- 3.44 查询本月过生日的学生
- 3.45 查询下个月过生日的学生
1. SQL执行顺序
1.from
2.join
3.on
4.where
5.group by(开始使用select中的别名,后面的语句中都可以使用)
6.avg,sum
7.having
8.select
9.distinct
10.order by
11.limit
2. 开窗函数
SQL中的开窗函数介绍
(本来打算自己总结,但是发现有小伙伴总结的很好,再此引用一下)
3. 经典SQL题
3.0 数据准备
## 学生表
CREATE TABLE `student` (
`SId` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`Sname` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`Sage` datetime(0) NULL DEFAULT NULL,
`Ssex` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
INSERT INTO `student` VALUES ('01', '赵雷', '1990-01-01 00:00:00', '男');
INSERT INTO `student` VALUES ('02', '钱电', '1990-12-21 00:00:00', '男');
INSERT INTO `student` VALUES ('03', '孙风', '1990-05-20 00:00:00', '男');
INSERT INTO `student` VALUES ('04', '李云', '1990-08-06 00:00:00', '男');
INSERT INTO `student` VALUES ('05', '周梅', '1991-12-01 00:00:00', '女');
INSERT INTO `student` VALUES ('06', '吴兰', '1992-03-01 00:00:00', '女');
INSERT INTO `student` VALUES ('07', '郑竹', '1999-07-01 00:00:00', '女');
INSERT INTO `student` VALUES ('09', '张三', '2017-12-20 00:00:00', '女');
INSERT INTO `student` VALUES ('10', '李四', '2017-12-25 00:00:00', '女');
INSERT INTO `student` VALUES ('11', '李四', '2017-12-30 00:00:00', '女');
INSERT INTO `student` VALUES ('12', '赵六', '2017-01-01 00:00:00', '女');
INSERT INTO `student` VALUES ('13', '孙七', '2018-01-01 00:00:00', '女');
## 课程表
CREATE TABLE `course` (
`CID` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`Cname` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`TId` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
INSERT INTO `course` VALUES ('01', '语文', '02');
INSERT INTO `course` VALUES ('02', '数学', '01');
INSERT INTO `course` VALUES ('03', '英语', '03');
## 选课表
CREATE TABLE `sc` (
`SId` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`CID` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`score` decimal(18, 1) NULL DEFAULT NULL
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
INSERT INTO `sc` VALUES ('01', '01', 80.0);
INSERT INTO `sc` VALUES ('01', '02', 90.0);
INSERT INTO `sc` VALUES ('01', '03', 99.0);
INSERT INTO `sc` VALUES ('02', '01', 70.0);
INSERT INTO `sc` VALUES ('02', '02', 60.0);
INSERT INTO `sc` VALUES ('02', '03', 80.0);
INSERT INTO `sc` VALUES ('03', '01', 80.0);
INSERT INTO `sc` VALUES ('03', '02', 80.0);
INSERT INTO `sc` VALUES ('03', '03', 80.0);
INSERT INTO `sc` VALUES ('04', '01', 50.0);
INSERT INTO `sc` VALUES ('04', '02', 30.0);
INSERT INTO `sc` VALUES ('04', '03', 20.0);
INSERT INTO `sc` VALUES ('05', '01', 76.0);
INSERT INTO `sc` VALUES ('05', '02', 87.0);
INSERT INTO `sc` VALUES ('06', '01', 31.0);
INSERT INTO `sc` VALUES ('06', '03', 34.0);
INSERT INTO `sc` VALUES ('07', '02', 89.0);
INSERT INTO `sc` VALUES ('07', '03', 98.0);
## 教师表
CREATE TABLE `teacher` (
`TId` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`Tname` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
INSERT INTO `teacher` VALUES ('01', '张三');
INSERT INTO `teacher` VALUES ('02', '李四');
INSERT INTO `teacher` VALUES ('03', '王五');
3.1 ☆ 查询‘01’课程比‘02’课程成绩高的学生
-- 1.查询‘01’课程比‘02’课程成绩高的学生
select
*
from student a
inner join sc b on a.SId = b.SId
inner join sc c on a.SId = c.SId and b.CID='01' and c.CID='02'
where b.score > c.score
-- 1.1查询同时存在‘01’课程和‘02’课程的情况
-- 写法一:
select * from (select * from sc where Cid='01') a
inner join (select * from sc where Cid='02') b on a.SId=b.Sid;
-- 写法二:
select * from sc a
inner join sc b on a.Sid = b.SId and a.Cid='01' and b.CID='02'
-- 1.2查询存在‘01’课程但可能不存在‘02’可能的情况(不存在时显示为null)
-- 写法一:
select * from (select * from sc where cid = '01') a
left join sc b on a.sid = b.sid and b.cid = '02';
-- 写法二:
select * from sc a
left join sc b on a.sid = b.sid and b.cid = '02' where a.cid = '01'
-- 1.3查询不存在‘01’课程但存在‘02’课程的情况
select * from sc
where sid not in (select sid from sc where cid ='01') and cid = '02'
3.2 查询平均成绩大于等于60分的同学的学生编号和学生姓名和平均成绩
-- 2. 查询平均成绩大于等于60分的同学的学生编号和学生姓名和平均成绩
select a.sid,a.sname,b.avg_score from student a
inner join (select sid,AVG(score) as avg_score from sc GROUP BY sid having AVG(score) >= 60) b
on a.SId = b.SId
3.3 查询在SC表存在成绩的学生信息
-- 3. 查询在SC表存在成绩的学生信息
-- 写法一:
select * from student where sid in (select sid from sc group by sid)
-- 写法二:
select * from (select sid from sc GROUP BY sid) a left join student b on a.sid = b.sid
3.4 查询所有同学的学生编号、学生姓名、选课总数、所有课程的总成绩(没成绩的显示null)
-- 4. 查询所有同学的学生编号、学生姓名、选课总数、所有课程的总成绩(没成绩的显示null)
select a.sid,a.sname,b.cnum,b.snum from student a
left join (select sid,count(cid) as cnum,sum(score) as snum from sc GROUP BY sid) b
on a.sid = b.sid
-- 4.1 查有成绩的学生信息
-- 写法一:
select * from student where sid in (select sid from sc GROUP BY sid)
-- 写法二:
select b.* from (select sid from sc GROUP BY sid) a
left join student b on a.sid = b.sid
3.5 查询【李】姓老师的数量
-- 5. 查询【李】姓老师的数量
select count(1) from teacher where tname like '李%'
3.6 查询学过【张三】老师授课的同学的信息
-- 6. 查询学过【张三】老师授课的同学的信息
select d.* from teacher a
inner join course b on a.tid = b.tid
inner join sc c on b.cid = c.cid
inner join student d on c.sid = d.sid
where a.tname = '张三'
3.7 查询没有学全所有课程的同学的信息
-- 7. 查询没有学全所有课程的同学的信息
select a.*,b.cnum from student a
left join (select sid,count(cid) as cnum from sc GROUP BY sid) b on a.sid = b.sid
where b.cnum < (select count(cid) from course) or b.cnum is null
3.8 查询至少有一门课与学号为‘01’的同学所学相同的同学的信息
-- 8. 查询至少有一门课与学号为‘01’的同学所学相同的同学的信息
select a.* from student a
inner join (select DISTINCT sid from sc where cid in (select cid from sc where sid = '01')) b
on a.sid = b.sid
3.9 ☆ 查询和‘01’号同学学习的课程完全相同的其他同学的信息
-- 9.查询和‘01’号同学学习的课程完全相同的其他同学的信息
select a.* from student a inner join
(select sid from sc where sid not in (select distinct sid from sc where cid not in (select cid from sc where sid = '01')) and sid != '01'
GROUP BY sid having count(cid) = (select count(cid) from sc where sid = '01')) b
on a.sid = b.sid
3.10 ☆ 查询没学过【张三】老师讲授的任意门课程的学生姓名
-- 10. 查询没学过【张三】老师讲授的任意门课程的学生姓名
-- 写法一:
select a.sname from student a
where a.sid not in
(select DISTINCT sid from sc where cid = (select cid from course where tid = (select tid from teacher where tname = '张三' )))
-- 写法二:
select sname from student where sid not in (
select sid from sc a
left join course b on a.cid = b.cid
inner join teacher c on b.tid = c.tid
where c.tname = '张三')
3.11 查询两门及以上不合格课程的同学的学号,姓名及其平均成绩
-- 11. 查询两门及以上不合格课程的同学的学号,姓名及其平均成绩
select a.sid,a.sname,c.avg_score from student a
inner join
(select sid,count(cid) as cnum
from sc where score < 60
GROUP BY sid having count(cid) >= 2) b on a.sid = b.sid
inner join (select sid,avg(score) as avg_score from sc GROUP BY sid) c on b.sid = c.sid
3.12 检索‘01’课程分数小于60,按分数降序排列的学生信息
-- 12. 检索‘01’课程分数小于60,按分数降序排列的学生信息
select a.*,b.score from student a inner JOIN sc b on a.sid = b.sid
where b.cid = '01' and b.score < 60 ORDER BY b.score desc
3.13 按平均成绩的高到低显示所有学生的所有课程的成绩以及平均成绩
-- 13. 按平均成绩的高到低显示所有学生的所有课程的成绩以及平均成绩
select a.sid,b.cid,c.score,d.avg_score from student a
inner join course b
left join sc c on a.sid = c.sid and b.cid = c.cid
left join (select sid,avg(score) as avg_score from sc GROUP BY sid) d on a.sid = d.sid
ORDER BY d.avg_score desc
3.14 ☆ 查询各科成绩最高分、最低分和平均分
-- 14. 查询各科成绩最高分、最低分和平均分
select a.*,b.cname from
(select
cid,count(sid) as 选修人数,
max(score) as 最高分,
min(score) as 最低分,
avg(score) as 平均分,
sum(case when score>=60 then 1 else 0 end)/count(sid) as 及格率,
sum(case when score>=70 and score <80 then 1 else 0 end)/count(sid) as 中等率,
sum(case when score>=80 and score <90 then 1 else 0 end)/count(sid) as 优良率,
sum(case when score>=90 then 1 else 0 end)/count(sid) as 优秀率
from sc GROUP BY cid ORDER BY 选修人数 desc,cid asc) a
inner join course b on a.cid = b.cid
3.15 ☆ 按各科成绩进行排序,并显示排名,Score重复时也继续排名
-- 15. 按各科成绩进行排序,并显示排名,Score重复时也继续排名
select *,row_number() over (partition by cid ORDER BY score desc) as 排名 from sc;
-- 15.1 按各科成绩进行排序,并显示排名,Score重复时合并名次
-- 写法一:
select *,dense_rank() over (partition by cid ORDER BY score desc) as 排名from sc;
--写法二:
select *, rank() over (partition by cid ORDER BY score desc) as 排名 from sc;
3.16 ☆ 查询学生的总成绩,并进行排名,总分重复时保留名次空缺
-- 16. 查询学生的总成绩,并进行排名,总分重复时保留名次空缺
select sid,sum(score) as '总成绩',rank() over (ORDER BY sum(score) desc) as '排名'
from sc group by sid
-- 16.1 查询学生的总成绩,并进行排名,总分重复时不保留名次空缺
select sid,sum(score) as '总成绩',dense_rank() over (ORDER BY sum(score) desc) as '排名'
from sc group by sid
3.17 ☆ 统计各科成绩各分数段人数
-- 17. 统计各科成绩个分数段人数:
select a.*,b.cname from
(select cid,concat(sum(case when score<=100 and score >=85 then 1 else 0 end)/count(sid),'%') as '[100-85]',
concat(sum(case when score<=85 and score >=70 then 1 else 0 end)/count(sid),'%') as '[85-70]',
concat(sum(case when score<=70 and score >=60 then 1 else 0 end)/count(sid),'%') as '[70-60]',
concat(sum(case when score<=60 and score >=0 then 1 else 0 end)/count(sid),'%') as '[60-0]'
from sc GROUP BY cid
) a left join course b on a.cid = b.cid
3.18 ☆ 查询各科成绩前三名的记录
-- 18.查询各科成绩前三名的记录
select * from
(select *,dense_rank() over(partition by cid ORDER BY score desc) as 排名 from sc) a where a.排名 in (1,2,3)
3.19 查询每一门课程被选修的学生数
-- 19.查询每一门课程被选修的学生数
select cid,count(sid) from sc GROUP BY cid
3.20 查询出只选修两门课程的学生学号和姓名
-- 20.查询出只选修两门课程的学生学号和姓名
select a.sid,a.sname from student a
inner join (select sid from sc GROUP BY sid having count(cid) = 2) b on a.sid = b.sid
3.21 查询男生、女生人数
-- 21. 查询男生、女生人数
select ssex,count(sid) from student GROUP BY ssex
3.22 查询名字中含有【风】字的学生信息
-- 22.查询名字中含有【风】字的学生信息
select * from student where sname like '%风%'
3.23 查询同名同性学生名单,并统计同名同性人数
-- 23.查询同名同性学生名单,并统计同名同性人数
select sname,ssex,count(a.sid) as num
from
(select a.* from student a
inner join student b where a.sid != b.sid and a.sname = b.sname and a.ssex = b.ssex
) a GROUP BY sname,ssex
3.24 查询1990年出生的学生名单
-- 24. 查询1990年出生的学生名单
-- 写法一:
select * from student where year(sage) ='1990'
-- 写法二:
select * from student where left(sage,4) ='1990'
-- 写法三:
select * from student where substr(sage,1,4) ='1990'
3.25 查询每门课程的平均成绩,结果按平均成绩降序排列,平均成绩相同时,按课程编号升序排列
-- 25. 查询每门课程的平均成绩,结果按平均成绩降序排列,平均成绩相同时,按课程编号升序排列
select cid,avg(score) as avg_score
from sc GROUP BY cid ORDER BY avg_score desc,cid asc;
3.26 查询平均成绩大于等于 85 的所有学生的学号、姓名和平均成绩
-- 26.查询平均成绩大于等于 85 的所有学生的学号、姓名和平均成绩
select a.sid,b.sname,a.avg_score
from
(select sid,avg(score) as avg_score from sc GROUP BY sid having avg(score)>=85) a
left join student b on a.sid = b.sid
3.27 查询课程名称【数学】,且分数低于60的学生姓名和分数
-- 27. 查询课程名称【数学】,且分数低于60的学生姓名和分数
-- 写法一:
select c.sname,a.score from sc a
inner join course b on a.cid = b.cid
left join student c on a.sid = c.sid
where b.cname = '数学' and a.score < 60
-- 写法二:
select b.sname,a.score from sc a
left join student b on a.sid = b.sid
where a.cid = (select cid from course where cname='数学') and a.score < 60
3.28 询所有学生的课程及分数情况(存在学生没成绩,没选课的情况)
-- 28. 查询所有学生的课程及分数情况(存在学生没成绩,没选课的情况)
select * from student a left join sc c on a.sid = c.sid
3.29 查询任何一门课程成绩在70分以上的姓名、课程名称和分数
-- 29. 查询任何一门课程成绩在70分以上的姓名、课程名称和分数
select b.sname,c.cname,a.score from sc a
left join student b on a.sid = b.sid
left join course c on a.cid = c.cid
where a.score>70
3.30 查询存在不及格的课程
-- 30. 查询存在不及格的课程
-- 方法一:
select b.* from sc a
inner join course b on a.cid = b.cid where a.score < 60 GROUP BY a.cid
-- 方法二:
select * from course where cid in (select distinct cid from sc where score<60)
3.31 查询课程编号为01且课程成绩在80分以上的学生的学号和姓名
-- 31.查询课程编号为01且课程成绩在80分以上的学生的学号和姓名
select a.sid,b.sname from sc a
left join student b on a.sid = b.sid where a.cid = '01' and a.score >= 80
3.32 求每门课程的学生人数
-- 32.求每门课程的学生人数
select cid,count(sid) as snum from sc GROUP BY cid
3.33 ☆ 假设成绩不重复,查询选修【张三】老师所授课程的学生中,成绩最高的学生信息及其成绩
-- 33. 假设成绩不重复,查询选修【张三】老师所授课程的学生中,成绩最高的学生信息及其成绩
select d.*,a.* from sc a
inner join course b on a.cid = b.cid
inner join teacher c on b.tid = c.tid and c.tname='张三'
left join student d on a.sid = d.sid ORDER BY a.score desc limit 1
3.34 ☆ 假设成绩有重复的情况下,查询选修【张三】老师所授课程的学生中,成绩最高的学生信息及其成绩
-- 34. 假设成绩有重复的情况下,查询选修【张三】老师所授课程的学生中,成绩最高的学生信息及其成绩
select *
from
(select d.*,a.score,c.tname,dense_rank() over (ORDER BY a.score desc) as pm from sc a
inner join course b on a.cid = b.cid
inner join teacher c on b.tid = c.tid and c.tname='张三'
left join student d on a.sid = d.sid ) a where a.pm = 1
3.35 查询不同课程成绩相同的学生的学生编号、课程编号、学生成绩
-- 35. 查询不同课程成绩相同的学生的学生编号、课程编号、学生成绩
select distinct a.* from sc a
inner join sc b on a.sid = b.sid and a.cid != b.cid and a.score = b.score
3.36 ☆ 查询每门科目成绩最好的前两名
-- 36. 查询每门科目成绩最好的前两名
select *
from
(select *,dense_Rank() over(partition by cid order by score desc) as pm from sc) a
where a.pm in (1,2)
3.37 统计每门课程的学生选修人数(超过5人的课程才统计)
-- 37. 统计每门课程的学生选修人数(超过5人的课程才统计)
select cid,count(sid) as num from sc GROUP BY cid having num>5
3.38 检索至少选修两门课程的学生学号
-- 38. 检索至少选修两门课程的学生学号
select sid,count(cid) as num from sc GROUP BY sid having num >= 2
3.39 查询选修了全部课程的学生信息
-- 39. 查询选修了全部课程的学生信息
-- 写法一:
select b.* from sc a
left join student b on a.sid = b.sid
group by a.sid having count(a.cid) = (select count(cid) from course)
-- 写法二:
select * from student
where sid in (select sid from sc GROUP BY sid having count(cid) = (select count(cid) from course))
3.40 查询各学生的年龄,只按年份来算
-- 40. 查询各学生的年龄,只按年份来算
select sid,sname,(year(now())-year(sage)) as age from student
3.41 ☆ 查询各学生的年龄,按出生日期来算,当前月日 < 出生年月的月日则,年龄减一
-- 41. 查询各学生的年龄,按出生日期来算,当前月日 < 出生年月的月日则,年龄减一
select sid,sname, timestampdiff(year,sage,now()) as age from student
select timestampdiff(year,'1990-02-01 00:00:00','2020-01-01 00:00:00');
select timestampdiff(year,'1990-02-01 00:00:00','2020-04-01 00:00:00')
select timestampdiff(day,'1990-02-01 00:00:00','1990-03-01 00:00:00')
select timestampdiff(hour,'1990-02-01 00:00:00','1990-02-02 00:00:00')
3.42 查询本周过生日的学生
-- 42. 查询本周过生日的学生
select * from student where week(now()) = week(sage)
3.43 查询下周过生日的学生
-- 43. 查询下周过生日的学生
select * from student where week(now())+1 = week(sage)
3.44 查询本月过生日的学生
-- 44. 查询本月过生日的学生
select * from student where month(now()) = month(sage)
3.45 查询下个月过生日的学生
-- 45. 查询下个月过生日的学生
select * from student where month(now())+1 = month(sage)