- 作业数据准备。(直接复制进去即可)
``sql -- 创建数据库 DROP DATABASE IF EXISTS
final_assignment; CREATE DATABASE IF NOT EXISTS
final_assignmentcharset='utf8mb4'; USE
final_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”的课程成绩高的所有学生的学号。
```sql
SELECT s1.sid FROM score AS s1
INNER JOIN score AS s2
ON s1.cid = '01' AND s2.cid = '02'
AND s1.sid = s2.sid
WHERE s1.score > s2.score;
查询平均成绩大于60分的学生的学号和平均成绩。
SELECT
sid,
ROUND(AVG(score), 2) AS avg_sco
FROM score
GROUP BY sid
HAVING avg_sco > 60;
查询所有学生的学号、姓名、选课数、总成绩。
SELECT
stu.sid,
stu.sname,
COUNT(sco.cid) AS 选课数,
SUM(IFNULL(sco.score, 0)) AS 总成绩
FROM student AS stu
LEFT OUTER JOIN score AS sco on stu.sid = sco.sid
GROUP BY sco.sid;
查询姓“张”的老师的个数。
SELECT COUNT(*) FROM teacher
WHERE 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 teacher
INNER JOIN course AS c ON teacher.tid = c.tid
INNER JOIN score AS s ON c.cid = s.cid
WHERE tname = '张三';
-- 接着,按照学号分组,统计出这些学生上了几门张三老师的课。
SELECT
sid,
COUNT(s.cid)
FROM teacher
INNER JOIN course AS c ON teacher.tid = c.tid
INNER JOIN score AS s ON c.cid = s.cid
WHERE tname = '张三'
GROUP BY sid;
-- 然后查询出张三老师教授课程的数量。
SELECT COUNT(cid) FROM teacher
INNER JOIN course AS c ON teacher.tid = c.tid
WHERE tname = '张三';
-- 接着过滤出学过张三老师所有课程的学生。
-- 学过张三老师所有课程就是“学生上的张三老师的课数量 = 张三老师教授课程的数量”
SELECT
sid,
COUNT(s.cid)
FROM teacher
INNER JOIN course AS c ON teacher.tid = c.tid
INNER JOIN score AS s ON c.cid = s.cid
WHERE tname = '张三'
GROUP BY sid
HAVING COUNT(s.cid) = (
SELECT COUNT(cid) FROM teacher
INNER JOIN course AS c ON teacher.tid = c.tid
WHERE tname = '张三'
);
-- 最后,用学号去连接学生表,即可得到最后的结果
SELECT
sco.sid,
stu.sname
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 = '张三'
GROUP BY sco.sid
HAVING COUNT(sco.cid) = (
SELECT COUNT(sco.cid) FROM teacher
INNER JOIN course AS c ON teacher.tid = c.tid
WHERE 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”的总成绩。
```sql
SELECT 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;
-- 查询出每个学生学习的课程数。
SELECT
sid,
COUNT(cid) AS course_num
FROM score
GROUP BY sid;
-- 筛选出没有学全所有课的学生信息。
SELECT
sid,
COUNT(cid) AS course_num
FROM score
GROUP BY sid
HAVING course_num < (
SELECT COUNT(*) FROM course
);
-- 连接学生表,得到最终结果
SELECT
stu.sid,
stu.sname,
COUNT(cid) AS course_num
FROM score RIGHT OUTER JOIN student AS stu on score.sid = stu.sid
GROUP BY sid
HAVING 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函数内进行排序。
SELECT
sid,
GROUP_CONCAT(cid ORDER BY cid) AS all_sid
FROM score
GROUP BY sid;
-- 查询出sid=01的所有课程号。
SELECT GROUP_CONCAT(cid ORDER BY cid) FROM score WHERE sid = '01';
-- 筛选出学号不为01,但是课程号与sid=01完全相同的学生学号。
SELECT sid FROM score
GROUP BY sid
HAVING 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”号的同学学习的课程完全相同的其他同学学号和姓名。
```sql
SELECT sid FROM score
GROUP BY sid
HAVING 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, score
FROM score AS sco
INNER JOIN student AS stu on sco.sid = stu.sid
WHERE cid = '01' AND score < 60
ORDER BY score DESC;
查询各科成绩最高和最低的分:以如下的形式显示:课程ID,最高分,最低分。
SELECT
cid,
MAX(score) AS max_sco,
MIN(score) AS min_sco
FROM score
GROUP BY cid;
查询不同老师所教不同课程平均分从高到低显示。
SELECT
t.tid,
t.tname,
c.cid,
avg(score) 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
GROUP BY t.tid, c.cid
ORDER BY avg_sco DESC;
查询学生平均成绩及其名次。
SELECT
sid,
AVG(IFNULL(score, 0)) AS avg_soc,
RANK() OVER (
ORDER BY AVG(IFNULL(score, 0)) DESC
) AS ranking
FROM score
GROUP BY sid;
查询各科成绩前三名的记录。
SELECT cid, sid, ranking FROM (
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY cid
ORDER BY score DESC
) AS ranking
FROM score
) AS tmp
WHERE ranking <= 3;
查询每门课程被选修的学生数。
SELECT
cid,
COUNT(sid) AS count_num
FROM score
GROUP BY cid;
查询出只选修了两门课程的全部学生的学号和姓名。
SELECT
stu.sid,
stu.sname
FROM score AS sco
INNER JOIN student AS stu ON sco.sid = stu.sid
GROUP BY stu.sid
HAVING COUNT(cid) = 2;
查询男生、女生人数。
SELECT
ssex,
COUNT(sid) AS count_num
FROM student
GROUP BY ssex;
查询名字中含有“风”字的学生信息。
SELECT * FROM student WHERE INSTR(sname, '风');
查询同名同性学生名单并统计同名人数。
-- 同名就是按照名字分组,同性就是按照性别分组。
-- 若有同名同姓,就代表着同一组的数量要大于等于2。
SELECT
sname,
ssex,
COUNT(*)
FROM student
GROUP BY sname, ssex
HAVING COUNT(*) >= 2;
1990年出生的学生名单。
SELECT * FROM student
WHERE YEAR(sbirthday) = 1990;
查询平均成绩大于85的所有学生的学号、姓名和平均成绩。
SELECT
stu.sid,
stu.sname,
AVG(score) AS avg_sco
FROM student AS stu
INNER JOIN score AS sco ON stu.sid = sco.sid
GROUP BY stu.sid
HAVING AVG(score) > 85;
查询每门课程的平均成绩,结果按平均成绩升序排序,平均成绩相同时,按课程号降序排列。
SELECT cid, AVG(score) AS avg_sco
FROM score
GROUP BY cid
ORDER BY avg_sco, cid DESC;
查询课程名称为“数学”且分数低于60的学生姓名和分数。
SELECT
stu.sname,
sco.score
FROM student AS stu
INNER JOIN score AS sco on stu.sid = sco.sid
INNER JOIN course AS c ON sco.cid = c.cid
WHERE c.cname = '数学' AND sco.score < 60;
查询所有学生的选课情况。
SELECT
stu.sid,
stu.sname,
IFNULL(GROUP_CONCAT(cname), '未选课') AS 选课情况
FROM student AS stu
LEFT OUTER JOIN score AS sco on stu.sid = sco.sid
LEFT OUTER JOIN course AS c on sco.cid = c.cid
GROUP BY sco.sid;
查询任何一门课程成绩在70分以上的姓名、课程名称和分数。
SELECT
stu.sname,
c.cname,
sco.score
FROM student AS stu
INNER JOIN score AS sco on stu.sid = sco.sid
INNER JOIN course AS c on sco.cid = c.cid
WHERE sco.score > 70;
查询不及格的课程并按课程号从大到小排列。
SELECT DISTINCT cid FROM score
WHERE score < 60
ORDER BY cid DESC;
查询课程编号为03且课程成绩在80分以上的学生的学号和姓名。
SELECT
stu.sid,
stu.sname
FROM score AS sco
INNER JOIN student AS stu ON sco.sid = stu.sid
WHERE 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;
- 查询各个课程及相应的选修人数。
```sql
SELECT
cid,
COUNT(sid)
FROM score
GROUP BY cid;
查询不同课程成绩相同的学生的学生编号、课程编号、学生成绩。
SELECT * FROM score AS s1
INNER JOIN score AS s2
ON s1.sid = s2.sid -- 学生编号相同,代表是同一个人
AND s1.score = s2.score -- 两门课的成绩相同
AND s1.cid != s2.cid; -- 课程号不同,表示是两门课
查询每门课程成绩最好的前两名。
SELECT * FROM (
SELECT *, ROW_NUMBER() OVER (
PARTITION BY cid
ORDER BY score DESC
) AS ranking
FROM score
) AS tmp WHERE ranking <= 2;
统计每门课程的学生选修人数(超过5人的课程才统计)。要求输出课程号和选修人数,查询结果按人数降序排序,若人数相同,按课程号升序排序。
SELECT
cid,
COUNT(sid) AS num
FROM score
GROUP BY cid
HAVING num > 5
ORDER BY num DESC, cid;
查询至少选修两门课程的学生学号。
SELECT sid
FROM score
GROUP BY sid
HAVING 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
-- 查询两门及以上不及格课程的学生学号。
SELECT
sid,
COUNT(cid) AS fail_num
FROM score
WHERE score < 60
GROUP BY sid
HAVING fail_num >= 2;
-- 查询所有学生的平均成绩。
SELECT sid, AVG(score) AS avg_sco FROM score
GROUP BY sid;
-- 二者连接,获取两门及以上不及格课程的同学的学号及其平均成绩。
SELECT
fail_stu.sid,
all_stu.avg_sco
FROM (
SELECT sid, COUNT(cid) AS fail_num
FROM score
WHERE score < 60
GROUP BY sid
HAVING fail_num >= 2
) AS fail_stu LEFT OUTER JOIN (
SELECT sid, AVG(score) AS avg_sco FROM score
GROUP BY sid
) AS all_stu ON fail_stu.sid = all_stu.sid;
检索课程编号为“03”且分数小于60的学生学号,结果按分数降序排列。
SELECT sid FROM score
WHERE cid = '03' AND score < 60
ORDER 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)
SELECT
c.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_rate
FROM score AS s
INNER JOIN course AS c on s.cid = c.cid
GROUP BY c.cid
ORDER BY avg_sco, pass_rate DESC;
查询本周过生日的学生。
SELECT * FROM (
SELECT *,
CONCAT_WS('-', YEAR(NOW()), SUBSTR(sbirthday, 6)) AS new_bir
FROM student
) AS tmp
WHERE WEEK(NOW(), 1) = week(new_bir, 1);
查询下周过生日的学生。
SELECT * FROM (
SELECT *,
CONCAT_WS('-', YEAR(NOW()), SUBSTR(sbirthday, 6)) AS new_bir
FROM student
) AS tmp
WHERE WEEK(NOW(), 1) + 1 = week(new_bir, 1);
查询本月过生日的学生。
SELECT * FROM student
WHERE MONTH(sbirthday) = MONTH(NOW());
查询下月过生日的学生。
SELECT * FROM student
WHERE MONTH(sbirthday) = MONTH(NOW()) + 1;