- 作业数据准备。(直接复制进去即可)
``sql -- 创建数据库 DROP DATABASE IF EXISTSfinal_assignment; CREATE DATABASE IF NOT EXISTSfinal_assignmentcharset='utf8mb4'; USEfinal_assignment`;
— 创建学生表
DROP TABLE IF EXISTS student;
CREATE TABLE IF NOT EXISTS student (
sid VARCHAR(10) PRIMARY KEY COMMENT ‘学号’,
sname VARCHAR(20) NOT NULL COMMENT ‘姓名’,
sbirthday DATE NOT NULL COMMENT ‘生日’,
ssex CHAR(3) NOT NULL DEFAULT ‘男’
);
INSERT INTO student VALUES
(‘01’, ‘赵雷’, ‘1990-01-01’, ‘男’),
(‘02’, ‘钱电’, ‘1990-12-21’, ‘男’),
(‘03’, ‘孙风’, ‘1990-05-20’, ‘男’),
(‘04’, ‘李云’, ‘1990-08-06’, ‘男’),
(‘05’, ‘周梅’, ‘1991-12-01’, ‘女’),
(‘06’, ‘吴兰’, ‘1992-03-01’, ‘女’),
(‘07’, ‘郑竹’, ‘1989-07-01’, ‘女’),
(‘08’, ‘王菊’, ‘1990-01-20’, ‘女’);
SELECT * FROM student;
— 创建教师表
DROP TABLE IF EXISTS teacher;
CREATE TABLE IF NOT EXISTS teacher (
tid VARCHAR(10) PRIMARY KEY COMMENT ‘教师编号’,
tname VARCHAR(20) NOT NULL COMMENT ‘教师姓名’
);
INSERT INTO teacher VALUES
(‘01’, ‘张三’),
(‘02’, ‘李四’),
(‘03’, ‘王五’);
SELECT * FROM teacher;
— 创建课程表
DROP TABLE IF EXISTS course;
CREATE TABLE IF NOT EXISTS course (
cid VARCHAR(10) PRIMARY KEY COMMENT ‘课程编号’,
cname VARCHAR(20) NOT NULL COMMENT ‘课程名称’,
tid VARCHAR(10) NOT NULL COMMENT ‘老师编号’
);
INSERT INTO course VALUES
(‘01’, ‘语文’, ‘02’),
(‘02’, ‘数学’, ‘01’),
(‘03’, ‘英语’, ‘03’);
SELECT * FROM course;
— 创建成绩表
DROP TABLE IF EXISTS score;
CREATE TABLE IF NOT EXISTS score (
sid VARCHAR(10) COMMENT ‘学生编号’,
cid VARCHAR(10) COMMENT ‘课程编号’,
score FLOAT(4, 2) COMMENT ‘成绩’
);
INSERT INTO score VALUES
(‘01’, ‘02’, 90),
(‘01’, ‘01’, 80),
(‘01’, ‘03’, 99),
(‘02’, ‘01’, 70),
(‘02’, ‘02’, 60),
(‘02’, ‘03’, 80),
(‘03’, ‘01’, 80),
(‘03’, ‘02’, 80),
(‘03’, ‘03’, 80),
(‘04’, ‘01’, 50),
(‘04’, ‘02’, 30),
(‘04’, ‘03’, 20),
(‘05’, ‘01’, 76),
(‘05’, ‘02’, 87),
(‘06’, ‘01’, 31),
(‘06’, ‘03’, 34),
(‘07’, ‘02’, 89),
(‘07’, ‘03’, 98);
SELECT * FROM score;
- 查询课程编号为“01”的课程比“02”的课程成绩高的所有学生的学号。```sqlSELECT s1.sid FROM score AS s1INNER JOIN score AS s2ON s1.cid = '01' AND s2.cid = '02'AND s1.sid = s2.sidWHERE s1.score > s2.score;
查询平均成绩大于60分的学生的学号和平均成绩。
SELECTsid,ROUND(AVG(score), 2) AS avg_scoFROM scoreGROUP BY sidHAVING avg_sco > 60;
查询所有学生的学号、姓名、选课数、总成绩。
SELECTstu.sid,stu.sname,COUNT(sco.cid) AS 选课数,SUM(IFNULL(sco.score, 0)) AS 总成绩FROM student AS stuLEFT OUTER JOIN score AS sco on stu.sid = sco.sidGROUP BY sco.sid;
查询姓“张”的老师的个数。
SELECT COUNT(*) FROM teacherWHERE LEFT(tname, 1) = '张';
查询没学过“张三”老师课的学生的学号、姓名。 ```sql — 先找出学过张三老师课程的学生编号。 SELECT s.sid FROM teacher AS t INNER JOIN course AS c ON t.tid = c.tid INNER JOIN score AS s ON c.cid = s.cid WHERE t.tname = ‘张三’;
— 然后就可以反向找出没学过的学生信息。 SELECT sid, sname FROM student WHERE sid NOT IN ( SELECT s.sid FROM teacher AS t INNER JOIN course AS c ON t.tid = c.tid INNER JOIN score AS s ON c.cid = s.cid WHERE t.tname = ‘张三’ );
- 查询学过“张三”老师所教的所有课的同学的学号、姓名。```sql-- 先查询出张三老师的学生的学生编号。SELECT sid FROM teacherINNER JOIN course AS c ON teacher.tid = c.tidINNER JOIN score AS s ON c.cid = s.cidWHERE tname = '张三';-- 接着,按照学号分组,统计出这些学生上了几门张三老师的课。SELECTsid,COUNT(s.cid)FROM teacherINNER JOIN course AS c ON teacher.tid = c.tidINNER JOIN score AS s ON c.cid = s.cidWHERE tname = '张三'GROUP BY sid;-- 然后查询出张三老师教授课程的数量。SELECT COUNT(cid) FROM teacherINNER JOIN course AS c ON teacher.tid = c.tidWHERE tname = '张三';-- 接着过滤出学过张三老师所有课程的学生。-- 学过张三老师所有课程就是“学生上的张三老师的课数量 = 张三老师教授课程的数量”SELECTsid,COUNT(s.cid)FROM teacherINNER JOIN course AS c ON teacher.tid = c.tidINNER JOIN score AS s ON c.cid = s.cidWHERE tname = '张三'GROUP BY sidHAVING COUNT(s.cid) = (SELECT COUNT(cid) FROM teacherINNER JOIN course AS c ON teacher.tid = c.tidWHERE tname = '张三');-- 最后,用学号去连接学生表,即可得到最后的结果SELECTsco.sid,stu.snameFROM teacher AS tINNER JOIN course AS c ON t.tid = c.tidINNER JOIN score AS sco ON c.cid = sco.cidINNER JOIN student AS stu on sco.sid = stu.sidWHERE t.tname = '张三'GROUP BY sco.sidHAVING COUNT(sco.cid) = (SELECT COUNT(sco.cid) FROM teacherINNER JOIN course AS c ON teacher.tid = c.tidWHERE tname = '张三');
- 查询学过编号为“01”的课程并且也学过编号为“02”的课程的学生的学号、姓名。
```sql
— 用内连接查询出学过01和02课程的学生学号。
SELECT s01.sid FROM score AS s01
INNER JOIN score AS s02
ON s01.cid = '01' AND s02.cid = '02'AND s01.sid = s02.sid;
— 然后连接学生表,获取学生姓名即可。 SELECT s01.sid, s.sname FROM score AS s01 INNER JOIN score AS s02 ON s01.cid = ‘01’ AND s02.cid = ‘02’ AND s01.sid = s02.sid INNER JOIN student AS s ON s01.sid = s.sid;
- 查询课程编号为“02”的总成绩。```sqlSELECT SUM(score) FROM score WHERE cid = '02';
- 查询所有课程成绩小于60分的学生的学号、姓名。 ```sql — 首先获取每个学生的最高成绩。 SELECT sid, MAX(score) FROM score GROUP BY sid;
— 若该学生的最高成绩小于60,这就意味着这个学生的所有成绩都小于60。 SELECT sid, MAX(score) AS max_sco FROM score GROUP BY sid HAVING max_sco < 60;
— 接着连接学生表,即可获得结果 — 学号为08的王菊同学在成绩表中没有数据,因此需要处理一下空数据。 SELECT stu.sid, stu.sname FROM score AS sco RIGHT OUTER JOIN student AS stu on sco.sid = stu.sid GROUP BY sco.sid HAVING MAX(IFNULL(sco.score, 0)) < 60;
- 查询没有学全所有课的学生的学号、姓名。```sql-- 查询出课程的数量。SELECT COUNT(*) FROM course;-- 查询出每个学生学习的课程数。SELECTsid,COUNT(cid) AS course_numFROM scoreGROUP BY sid;-- 筛选出没有学全所有课的学生信息。SELECTsid,COUNT(cid) AS course_numFROM scoreGROUP BY sidHAVING course_num < (SELECT COUNT(*) FROM course);-- 连接学生表,得到最终结果SELECTstu.sid,stu.sname,COUNT(cid) AS course_numFROM score RIGHT OUTER JOIN student AS stu on score.sid = stu.sidGROUP BY sidHAVING course_num < (SELECT COUNT(*) FROM course);
- 查询至少有一门课与学号为“01”的学生所学课程相同的学生的学号和姓名。 ```sql — 找到学号为“01”的学生所学的所有课程号。 SELECT cid FROM score WHERE sid = ‘01’;
— 查询选择了步骤一结果中的课程号的学生(除了学号为01的之外) SELECT * FROM score WHERE cid IN ( SELECT cid FROM score WHERE sid = ‘01’ ) AND sid != ‘01’;
— 关联学生表,获取学生姓名。 SELECT DISTINCT stu.sid, stu.sname FROM score AS sco INNER JOIN student AS stu on sco.sid = stu.sid WHERE cid IN ( SELECT cid FROM score WHERE sid = ‘01’ ) AND sco.sid != ‘01’;
- 查询和“01”号同学所学课程完全相同的其他同学的学号。```sql-- 用GROUP_CONCAT连接所有课程号。-- 连接时为了避免先后顺序不一致,在GROUP_CONCAT函数内进行排序。SELECTsid,GROUP_CONCAT(cid ORDER BY cid) AS all_sidFROM scoreGROUP BY sid;-- 查询出sid=01的所有课程号。SELECT GROUP_CONCAT(cid ORDER BY cid) FROM score WHERE sid = '01';-- 筛选出学号不为01,但是课程号与sid=01完全相同的学生学号。SELECT sid FROM scoreGROUP BY sidHAVING sid != '01' AND GROUP_CONCAT(cid ORDER BY cid) = (SELECT GROUP_CONCAT(cid ORDER BY cid) FROM score WHERE sid = '01');
- 把“score”表中“张三”老师教的课的成绩都更改为此课程的平均成绩。 ```sql — 获取张三老师所授课程的平均成绩。 SELECT s.cid, ROUND(AVG(score), 2) AS avg_sco FROM teacher AS t INNER JOIN course AS c on t.tid = c.tid INNER JOIN score AS s on c.cid = s.cid WHERE tname = ‘张三’ GROUP BY c.cid;
— 修改数据 UPDATE score JOIN ( SELECT s.cid, ROUND(AVG(score), 2) AS avg_sco FROM teacher AS t INNER JOIN course AS c on t.tid = c.tid INNER JOIN score AS s on c.cid = s.cid WHERE tname = ‘张三’ GROUP BY c.cid ) AS t ON score.cid = t.cid SET score.score = t.avg_sco;
— 验证结果 SELECT * FROM score;
- 查询和“02”号的同学学习的课程完全相同的其他同学学号和姓名。```sqlSELECT sid FROM scoreGROUP BY sidHAVING sid != '02' AND GROUP_CONCAT(cid ORDER BY cid) = (SELECT GROUP_CONCAT(cid ORDER BY cid) FROM score WHERE sid = '02');
检索”01”课程分数小于60,按分数降序排列的学生信息。
SELECT stu.*, cid, scoreFROM score AS scoINNER JOIN student AS stu on sco.sid = stu.sidWHERE cid = '01' AND score < 60ORDER BY score DESC;
查询各科成绩最高和最低的分:以如下的形式显示:课程ID,最高分,最低分。
SELECTcid,MAX(score) AS max_sco,MIN(score) AS min_scoFROM scoreGROUP BY cid;
查询不同老师所教不同课程平均分从高到低显示。
SELECTt.tid,t.tname,c.cid,avg(score) AS avg_scoFROM teacher AS tINNER JOIN course AS c ON t.tid = c.tidINNER JOIN score AS s ON c.cid = s.cidGROUP BY t.tid, c.cidORDER BY avg_sco DESC;
查询学生平均成绩及其名次。
SELECTsid,AVG(IFNULL(score, 0)) AS avg_soc,RANK() OVER (ORDER BY AVG(IFNULL(score, 0)) DESC) AS rankingFROM scoreGROUP BY sid;
查询各科成绩前三名的记录。
SELECT cid, sid, ranking FROM (SELECT*,ROW_NUMBER() OVER (PARTITION BY cidORDER BY score DESC) AS rankingFROM score) AS tmpWHERE ranking <= 3;
查询每门课程被选修的学生数。
SELECTcid,COUNT(sid) AS count_numFROM scoreGROUP BY cid;
查询出只选修了两门课程的全部学生的学号和姓名。
SELECTstu.sid,stu.snameFROM score AS scoINNER JOIN student AS stu ON sco.sid = stu.sidGROUP BY stu.sidHAVING COUNT(cid) = 2;
查询男生、女生人数。
SELECTssex,COUNT(sid) AS count_numFROM studentGROUP BY ssex;
查询名字中含有“风”字的学生信息。
SELECT * FROM student WHERE INSTR(sname, '风');
查询同名同性学生名单并统计同名人数。
-- 同名就是按照名字分组,同性就是按照性别分组。-- 若有同名同姓,就代表着同一组的数量要大于等于2。SELECTsname,ssex,COUNT(*)FROM studentGROUP BY sname, ssexHAVING COUNT(*) >= 2;
1990年出生的学生名单。
SELECT * FROM studentWHERE YEAR(sbirthday) = 1990;
查询平均成绩大于85的所有学生的学号、姓名和平均成绩。
SELECTstu.sid,stu.sname,AVG(score) AS avg_scoFROM student AS stuINNER JOIN score AS sco ON stu.sid = sco.sidGROUP BY stu.sidHAVING AVG(score) > 85;
查询每门课程的平均成绩,结果按平均成绩升序排序,平均成绩相同时,按课程号降序排列。
SELECT cid, AVG(score) AS avg_scoFROM scoreGROUP BY cidORDER BY avg_sco, cid DESC;
查询课程名称为“数学”且分数低于60的学生姓名和分数。
SELECTstu.sname,sco.scoreFROM student AS stuINNER JOIN score AS sco on stu.sid = sco.sidINNER JOIN course AS c ON sco.cid = c.cidWHERE c.cname = '数学' AND sco.score < 60;
查询所有学生的选课情况。
SELECTstu.sid,stu.sname,IFNULL(GROUP_CONCAT(cname), '未选课') AS 选课情况FROM student AS stuLEFT OUTER JOIN score AS sco on stu.sid = sco.sidLEFT OUTER JOIN course AS c on sco.cid = c.cidGROUP BY sco.sid;
查询任何一门课程成绩在70分以上的姓名、课程名称和分数。
SELECTstu.sname,c.cname,sco.scoreFROM student AS stuINNER JOIN score AS sco on stu.sid = sco.sidINNER JOIN course AS c on sco.cid = c.cidWHERE sco.score > 70;
查询不及格的课程并按课程号从大到小排列。
SELECT DISTINCT cid FROM scoreWHERE score < 60ORDER BY cid DESC;
查询课程编号为03且课程成绩在80分以上的学生的学号和姓名。
SELECTstu.sid,stu.snameFROM score AS scoINNER JOIN student AS stu ON sco.sid = stu.sidWHERE cid = '03' AND score > 80;
查询选了课程的学生人数。
SELECT COUNT(DISTINCT sid) FROM score;
查询选修“王五”老师所授课程的学生中成绩最高的学生姓名及其成绩。 ```sql — 先查询每个老师每门课程的最高分 SELECT stu.sid, stu.sname, t.tid, t.tname, c.cname, sco.score, MAX(score) OVER (
PARTITION BY t.tid, c.cid
) AS max_sco FROM teacher AS t INNER JOIN course AS c on t.tid = c.tid INNER JOIN score AS sco on c.cid = sco.cid INNER JOIN student AS stu on sco.sid = stu.sid;
— 接着查看王五老师每门课的最高分。 SELECT stu.sid, stu.sname, t.tid, t.tname, c.cname, sco.score, MAX(score) OVER (PARTITION BY t.tid, c.cid) AS max_sco FROM teacher AS t INNER JOIN course AS c on t.tid = c.tid INNER JOIN score AS sco on c.cid = sco.cid INNER JOIN student AS stu on sco.sid = stu.sid WHERE t.tname = ‘王五’;
— 筛选出分数与最高分相等的学生的学生姓名以及成绩。 SELECT * FROM ( SELECT stu.sid, stu.sname, t.tid, t.tname, c.cname, sco.score, MAX(score) OVER(PARTITION BY t.tid, c.cid) AS max_sco FROM teacher AS t INNER JOIN course AS c on t.tid = c.tid INNER JOIN score AS sco on c.cid = sco.cid INNER JOIN student AS stu on sco.sid = stu.sid WHERE t.tname = ‘王五’ ) AS t WHERE score = max_sco;
- 查询各个课程及相应的选修人数。```sqlSELECTcid,COUNT(sid)FROM scoreGROUP BY cid;
查询不同课程成绩相同的学生的学生编号、课程编号、学生成绩。
SELECT * FROM score AS s1INNER JOIN score AS s2ON s1.sid = s2.sid -- 学生编号相同,代表是同一个人AND s1.score = s2.score -- 两门课的成绩相同AND s1.cid != s2.cid; -- 课程号不同,表示是两门课
查询每门课程成绩最好的前两名。
SELECT * FROM (SELECT *, ROW_NUMBER() OVER (PARTITION BY cidORDER BY score DESC) AS rankingFROM score) AS tmp WHERE ranking <= 2;
统计每门课程的学生选修人数(超过5人的课程才统计)。要求输出课程号和选修人数,查询结果按人数降序排序,若人数相同,按课程号升序排序。
SELECTcid,COUNT(sid) AS numFROM scoreGROUP BY cidHAVING num > 5ORDER BY num DESC, cid;
查询至少选修两门课程的学生学号。
SELECT sidFROM scoreGROUP BY sidHAVING COUNT(cid) >= 2;
查询选修了全部课程的学生信息。 ```sql — 查询课程总数量。 SELECT COUNT(cid) FROM course;
— 查询选课数量等于课程总数量的学生学号。 SELECT sid FROM score GROUP BY sid HAVING COUNT(cid) >= ( SELECT COUNT(cid) FROM course );
— 连接学生表,获取学生信息。 SELECT stu.* FROM score AS sco LEFT OUTER JOIN student AS stu on sco.sid = stu.sid GROUP BY sid HAVING COUNT(cid) >= ( SELECT COUNT(cid) FROM course );
- 查询两门及以上不及格课程的同学的学号及其平均成绩。```sql-- 查询两门及以上不及格课程的学生学号。SELECTsid,COUNT(cid) AS fail_numFROM scoreWHERE score < 60GROUP BY sidHAVING fail_num >= 2;-- 查询所有学生的平均成绩。SELECT sid, AVG(score) AS avg_sco FROM scoreGROUP BY sid;-- 二者连接,获取两门及以上不及格课程的同学的学号及其平均成绩。SELECTfail_stu.sid,all_stu.avg_scoFROM (SELECT sid, COUNT(cid) AS fail_numFROM scoreWHERE score < 60GROUP BY sidHAVING fail_num >= 2) AS fail_stu LEFT OUTER JOIN (SELECT sid, AVG(score) AS avg_sco FROM scoreGROUP BY sid) AS all_stu ON fail_stu.sid = all_stu.sid;
检索课程编号为“03”且分数小于60的学生学号,结果按分数降序排列。
SELECT sid FROM scoreWHERE cid = '03' AND score < 60ORDER BY score DESC;
删除学生编号为“02”的课程编号为“01”的成绩。
DELETE FROM score WHERE sid = '02' AND cid = '01';
使用分段[85-100],[70-84],[60-69],[<60]来统计各科成绩,分别统计各分数段人数:课程ID和课程名称。 ```sql -- 先对所有成绩进行分段。 SELECT *, IF (score >= 85 AND score <= 100, 1, 0) AS ‘[85-100]’, IF (score >= 70 AND score <= 84, 1, 0) AS ‘[70-84]’, IF (score >= 60 AND score <= 69, 1, 0) AS ‘[60-69]’, IF (score <= 60, 1, 0) AS ‘[<60]’ FROM score AS s INNER JOIN course AS c on s.cid = c.cid;
— 接着统计每门课成每个分段的人数。(实际上就是把每个分段的0和1都加起来) SELECT c.cid, c.cname, SUM(IF (score >= 85 AND score <= 100, 1, 0)) AS ‘[85-100]’, SUM(IF (score >= 70 AND score <= 84, 1, 0)) AS ‘[70-84]’, SUM(IF (score >= 60 AND score <= 69, 1, 0)) AS ‘[60-69]’, SUM(IF (score <= 60, 1, 0)) AS ‘[<60]’ FROM score AS s INNER JOIN course AS c on s.cid = c.cid GROUP BY c.cid;
- 按各科平均成绩从低到高和及格率的百分数从高到低排列,以如下形式显示:课程号,课程名,平均成绩,及格百分数。```sql-- 合格率 = (该门课程大于60的人数 / 该门课程的总人数) * 100 %-- 该门课程大于60的人数:SELECT COUNT(score.sid) FROM score WHERE score.cid = c.cid AND score.score > 60-- c.cid是从外表传进来的参数-- 该门课程的总人数:COUNT(sid)SELECTc.cid,c.cname,AVG(score) AS avg_sco,CONCAT(ROUND((SELECT COUNT(score.sid) FROM score WHERE score.cid = c.cid AND score.score > 60) / COUNT(sid) * 100, 2),'%') AS pass_rateFROM score AS sINNER JOIN course AS c on s.cid = c.cidGROUP BY c.cidORDER BY avg_sco, pass_rate DESC;
查询本周过生日的学生。
SELECT * FROM (SELECT *,CONCAT_WS('-', YEAR(NOW()), SUBSTR(sbirthday, 6)) AS new_birFROM student) AS tmpWHERE WEEK(NOW(), 1) = week(new_bir, 1);
查询下周过生日的学生。
SELECT * FROM (SELECT *,CONCAT_WS('-', YEAR(NOW()), SUBSTR(sbirthday, 6)) AS new_birFROM student) AS tmpWHERE WEEK(NOW(), 1) + 1 = week(new_bir, 1);
查询本月过生日的学生。
SELECT * FROM studentWHERE MONTH(sbirthday) = MONTH(NOW());
查询下月过生日的学生。
SELECT * FROM studentWHERE MONTH(sbirthday) = MONTH(NOW()) + 1;
