超經典MySQL練習50題,做完這些你的SQL就過關了

鑑於 50 題篇幅太長,本文只展示了其中10題及筆者的思考,50 題完整版練習題以及筆者的答案實踐已整理在pdf檔案中,共有100多頁,在文末提供獲取的方法。

-- 建表
-- 學生表
CREATE TABLE `Student`(
`s_id` VARCHAR(20),
`s_name` VARCHAR(20) NOT NULL DEFAULT '',
`s_birth` VARCHAR(20) NOT NULL DEFAULT '',
`s_sex` VARCHAR(10) NOT NULL DEFAULT '',
PRIMARY KEY(`s_id`)
);
-- 課程表
CREATE TABLE `Course`(
`c_id` VARCHAR(20),
`c_name` VARCHAR(20) NOT NULL DEFAULT '',
`t_id` VARCHAR(20) NOT NULL,
PRIMARY KEY(`c_id`)
);
-- 教師表
CREATE TABLE `Teacher`(
`t_id` VARCHAR(20),
`t_name` VARCHAR(20) NOT NULL DEFAULT '',
PRIMARY KEY(`t_id`)
);
-- 成績表
CREATE TABLE `Score`(
`s_id` VARCHAR(20),
`c_id` VARCHAR(20),
`s_score` INT(3),
PRIMARY KEY(`s_id`,`c_id`)
);

-- 插入學生表測試資料
insert into Student values('01' , '趙雷' , '1990-01-01' , '男');
insert into Student values('02' , '錢電' , '1990-12-21' , '男');
insert into Student values('03' , '孫風' , '1990-05-20' , '男');
insert into Student values('04' , '李雲' , '1990-08-06' , '男');
insert into Student values('05' , '周梅' , '1991-12-01' , '女');
insert into Student values('06' , '吳蘭' , '1992-03-01' , '女');
insert into Student values('07' , '鄭竹' , '1989-07-01' , '女');
insert into Student values('08' , '王菊' , '1990-01-20' , '女');
-- 課程表測試資料
insert into Course values('01' , '語文' , '02');
insert into Course values('02' , '數學' , '01');
insert into Course values('03' , '英語' , '03');

-- 教師表測試資料
insert into Teacher values('01' , '張三');
insert into Teacher values('02' , '李四');
insert into Teacher values('03' , '王五');

-- 成績表測試資料
insert into Score values('01' , '01' , 80);
insert into Score values('01' , '02' , 90);
insert into Score values('01' , '03' , 99);
insert into Score values('02' , '01' , 70);
insert into Score values('02' , '02' , 60);
insert into Score values('02' , '03' , 80);
insert into Score values('03' , '01' , 80);
insert into Score values('03' , '02' , 80);
insert into Score values('03' , '03' , 80);
insert into Score values('04' , '01' , 50);
insert into Score values('04' , '02' , 30);
insert into Score values('04' , '03' , 20);
insert into Score values('05' , '01' , 76);
insert into Score values('05' , '02' , 87);
insert into Score values('06' , '01' , 31);
insert into Score values('06' , '03' , 34);
insert into Score values('07' , '02' , 89);
insert into Score values('07' , '03' , 98);

題目要求

SQL實現

-- 方法1
select
a.*
,b.s_score as 1_score
,c.s_score as 2_score
from Student a
join Score b on a.s_id = b.s_id and b.c_id = '01' -- 方法1兩個表透過學號連線,指定01
left join Score c on a.s_id = c.s_id and c.c_id='02' or c.c_id is NULL -- 指定02,或者c中的c_id直接不存在
-- 為NULL的條件可以不存在,因為左連線中會直接排除c表中不存在的資料,包含NULL
where b.s_score > c.s_score; -- 判斷條件


-- 方法2:直接使用where語句
select
a.*
,b.s_score as 1_score
,c.s_score as 2_score
from Student a, Score b, Score c
where a.s_id=b.s_id -- 列出全部的條件
and a.s_id=c.s_id
and b.c_id='01'
and c.c_id='02'
and b.s_score > c.s_score; -- 前者成績高

題目要求

SQL實現

-- 方法1:透過連線方式實現
select
a.*
,b.s_score as 1_score
,c.s_score as 2_score
from Student a
left join Score b on a.s_id=b.s_id and b.c_id='01' or b.c_id=NULL -- 包含NULL的資料
join score c on a.s_id=c.s_id and c.c_id='02'
where b.s_score < c.s_score;

-- 透過where子句實現
select
a.*
,b.s_score as 1_score
,c.s_score as 2_score
from Student a, Score b, Score c
where a.s_id=b.s_id
and a.s_id=c.s_id
and b.c_id='01'
and c.c_id='02'
and b.s_score < c.s_score; -- 前者比較小

題目需求

SQL實現

-- 執行順序:先執行分組,再執行avg平均操作
select
b.s_id
,b.s_name
,round(avg(a.s_score), 2) as avg_score
from Student b
join Score a
on b.s_id = a.s_id
group by b.s_id -- 分組之後查詢每個人的平均成績
having avg_score >= 60;

-- 附加題:總分超過200分的同學
select
b.s_id
,b.s_name
,round(sum(a.s_score),2) as sum_score -- sum求和
from Student b
join Score a
on b.s_id=a.s_id
group by b.s_id
having sum_score > 200;

題目要求

SQL實現1-兩種情況連線

select 
b.s_id
,b.s_name
,round(avg(a.s_score), 2) as avg_score -- round四捨五入函式
from Student b
join Score a
on b.s_id = a.s_id
group by b.s_id -- 分組之後查詢每個人的平均成績
having avg_score < 60;
select 
a.s_id
,a.s_name
,0 as avg_score
from Student a
where a.s_id not in ( -- 學生的學號不在給給定表的學號中
select distinct s_id -- 查詢出全部的學號
from Score
);

SQL實現2-ifnull函式判斷

select 
S.s_id
,S.s_name
,round(avg(ifnull(C.s_score,0)), 2) as avg_score -- ifnull 函数:第一个参数存在则取它本身,不存在取第二个值0
from Student S
left join Score C
on S.s_id = C.s_id
group by s_id
having avg_score < 60;
select 
a.s_id
,a.s_name
,ROUND(AVG(b.s_score), 2) as avg_score
from Student a
left join Score b on a.s_id = b.s_id
GROUP BY a.s_id
HAVING avg_score < 60 or avg_score is null; -- 最後的NULL判斷

題目需求

SQL實現

select 
a.s_id
,a.s_name
,count(b.c_id) as course_number -- 課程個數
,sum(b.s_score) as scores_sum -- 成績總和
from Student a
left join Score b
on a.s_id = b.s_id
group by a.s_id,a.s_name;

題目需求

SQL實現

select count(t_name) from Teacher where t_name like "李%";   -- 萬用字元

題目需求

SQL實現

-- 方法1:透過張三老師的課程的學生來查詢;自己的方法
select * -- 3. 透過學號找出全部學生資訊
from Student
where s_id in (
select s_id -- 2.透過課程找出對應的學號
from Score S
join Course C
on S.c_id = C.c_id -- 課程表和成績表
where C.t_id=(select t_id from Teacher where t_name="張三") -- 1.查詢張三老師的課程
);

-- 方法2:透過張三老師的課程來查詢
select s1.*
from Student s1
join Score s2
on s1.s_id=s2.s_id
where s2.c_id in (
select c_id from Course c where t_id=( -- 1. 透過老師找出其對應的課程
select t_id from Teacher t where t_name="張三"
)
)

-- 方法3
select s.* from Teacher t
left join Course c on t.t_id=c.t_id -- 教師表和課程表
left join Score sc on c.c_id=sc.c_id -- 課程表和成績表
left join Student s on s.s_id=sc.s_id -- 成績表和學生資訊表
where t.t_name='張三';

題目需求

SQL實現

select * -- 3. 通过学号找出全部学生信息
from Student
where s_id not in ( -- 2.通过学号取反:学号不在张三老师授课的学生的学号中
select s_id
from Score S
join Course C
on S.c_id = C.c_id
where C.t_id=(select t_id from Teacher where t_name ="张三") -- 1.查询张三老师的课程
);

-- 方法2:
select *
from Student s1
where s1.s_id not in (
select s2.s_id from Student s2 join Score s3 on s2.s_id=s3.s_id where s3.c_id in(
select c.c_id from Course c join Teacher t on c.t_id=t.t_id where t_name="張三"
)
);

-- 方法3
select s1.*
from Student s1
join Score s2
on s1.s_id=s2.s_id
where s2.c_id not in (
select c_id from Course c where t_id=( -- 1. 透過老師找出其對應的課程
select t_id from Teacher t where t_name="張三"
)
);

題目需求

SQL實現

-- 自己的方法:透過自連線實現
select s1.*
from Student s1
where s_id in (
select s2.s_id from Score s2
join Score s3
on s2.s_id=s3.s_id
where s2.c_id='01' and s3.c_id='02'
);

-- 方法2:直接透過where語句實現
select s1.*
from Student s1, Score s2, Score s3
where s1.s_id=s2.s_id
and s1.s_id=s3.s_id
and s2.c_id=01 and s3.c_id=02;

-- 方法3:兩個子查詢
-- 1. 先查出學號
select sc1.s_id
from (select * from Score s1 where s1.c_id='01') sc1,
(select * from Score s1 where s1.c_id='02') sc2
where sc1.s_id=sc2.s_id;

-- 2.找出學生資訊
select *
from Student
where s_id in (select sc1.s_id -- 指定學號是符合要求的
from (select * from Score s1 where s1.c_id='01') sc1,
(select * from Score s1 where s1.c_id='02') sc2
where sc1.s_id=sc2.s_id);

題目需求

SQL實現

select s1.*
from Student s1
where s_id not in ( -- 直接將上面一題的結果全部排出,導致那些沒有學過01課程的學生也出現了:07,08
select s2.s_id from Score s2
join Score s3
on s2.s_id=s3.s_id
where s2.c_id='01' and s3.c_id ='02'
);
select s1.*
from Student s1
where s_id in (
select s2.s_id from Score s2
join Score s3
on s2.s_id=s3.s_id
where s2.c_id='01' and s3.c_id !='02' -- 直接取反是不行的,因為修改(01,02,03)的同學也會出現
);
-- 方法1:根據兩種修課情況來判斷

select s1.*
from Student s1
where s1.s_id in (select s_id from Score where c_id='01') -- 修過01課程,要保留
and s1.s_id not in (select s_id from Score where c_id='02'); -- 哪些人修過02,需要排除
select * from Student where s_id in (
select s_id
from Score
where c_id='01' -- 修過01課程的學號
and s_id not in (select s_id -- 同時學號不能在修過02課程中出現
from Score
where c_id='02')
);

--

--

這是一個專注於數據分析職場的內容部落格,聚焦一批數據分析愛好者,在這裡,我會分享數據分析相關知識點推送、(工具/書籍)等推薦、職場心得、熱點資訊剖析以及資源大盤點,希望同樣熱愛數據的我們一同進步! 臉書會有更多互動喔:https://www.facebook.com/shujvfenxi/

Love podcasts or audiobooks? Learn on the go with our new app.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
數據分析那些事

數據分析那些事

這是一個專注於數據分析職場的內容部落格,聚焦一批數據分析愛好者,在這裡,我會分享數據分析相關知識點推送、(工具/書籍)等推薦、職場心得、熱點資訊剖析以及資源大盤點,希望同樣熱愛數據的我們一同進步! 臉書會有更多互動喔:https://www.facebook.com/shujvfenxi/