SQL经典题型解析:1-10题

已知是以下4张表:

–1.学生表

Student(s_id, s_name, s_birth, s_sex) –学生编号,学生姓名, 出生年月,学生性别

–2.课程表

Course(c_id, c_name, t_id) – –课程编号, 课程名称, 教师编号

–3.教师表

Teacher(t_id, t_name) –教师编号,教师姓名

–4.成绩表

Score(s_id, c_id, s_score) –学生编号,课程编号,分数

首先,我们需要搞清楚这4张表的关联关系,这样有助于编写对应的SQL语句。下面是我做的关于4个表的关联图:

关联关系

搞清表之间的关联关系后,开始创建数据库和表,我用的是navicat客户端。

1.创建表:

(1)学生表:

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`)

);

(2)成绩表:

CREATE TABLE `Score`(

`s_id` VARCHAR(20),

`c_id` VARCHAR(20),

`s_score` INT(3),

PRIMARY KEY(`s_id`,`c_id`)

);

(3)课程表:

CREATE TABLE `Course`(

`c_id` VARCHAR(20),

`c_name` VARCHAR(20) NOT NULL DEFAULT ' ',

`t_id` VARCHAR(20) NOT NULL,

PRIMARY KEY(`c_id`)

);

(4)教师表:

CREATE TABLE `Teacher`(

`t_id` VARCHAR(20),

`t_name` VARCHAR(20) NOT NULL DEFAULT ' ',

PRIMARY KEY(`t_id`)

);


2.插入数据

(1)插入学生表数据:

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','女');

(2)插入成绩表数据:

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);

(3)插入课程表数据:

insert into Course values('01','语文','02');

insert into Course values('02','数学','01');

insert into Course values('03','英语','03');

(4)插入教师表数据:

insert into Teacher values('01','张三');

insert into Teacher values('02','李四');

insert into Teacher values('03','王五');


以上4张表已创建完成并插入数据,下面详细解析经典题型

****-- 1、查询"01"课程比"02"课程成绩高的学生的信息及课程分数

理解题意:查询学生信息及01、02课程的成绩在'01'课程分数大于'02'课程条件下

分析思路:由于要查询学生信息和分数,那么需要用2个表,即"Student"和"Score"表,多表查询需要用到Join语句连接,要使用子查询查询各课程的成绩。

方法一:

#查询'01'课程的成绩

SELECT s_id, s_score as s1 From score where c_id='01';

#查询'02'课程的成绩

SELECT s_id, s_score as s2 From score where c_id='02';

(注:s1,s2 分别是'01'和'02'课程对应分数的别名,方便作比较)

#查询'01'课程分数>'02'课程分数的s_id,s1,s2

SELECT r1.s_id, s1,s2 From 

(SELECT s_id, s_score as s1 From score where c_id='01')r1,

(SELECT s_id, s_score as s2 From score where c_id='02')r2 

where r1.s_id=r2.s_id and s1>s2;

得到的结果集如下:

#使用JOIN连接"student"表,得到学生信息及课程成绩

SELECT * FROM Student s Right Join

(SELECT r1.s_id, s1,s2 From 

(SELECT s_id, s_score as s1 From score where c_id='01')r1,

(SELECT s_id, s_score as s2 From score where c_id='02')r2 

where r1.s_id=r2.s_id and s1>s2)R

On s.s_id=r.s_id;

最终结果应该是这样的:

方法二:

#使用INNER JOIN 连接子查询,将满足条件的s_id, s1,s2查询出来

SELECT r1.s_id, s1,s2 from

(SELECT s_id, s_score as s1 from score where c_id='01')r1

INNER JOIN

(SELECT s_id, s_score as s2 from score where c_id='02')r2

on r1.s_id=r2.s_id and s1>s2

#再使用INNER JOIN 连接Student表和上面的临时表R

SELECT s.* ,R.s1,R.s2 from student s

INNER JOIN

(SELECT r1.s_id, s1,s2 from

(SELECT s_id, s_score as s1 from score where c_id='01')r1

INNER JOIN

(SELECT s_id, s_score as s2 from score where c_id='02')r2

on r1.s_id=r2.s_id and s1>s2)R

on s.s_id=R.s_id;

得到如下结果:

与方法一一样

总结:方法一和方法二都能得到正确的结果,相较于方法二,方法一逻辑更清晰,语句较短,比较推荐。


-- 2、查询"01"课程比"02"课程成绩低的学生的信息及课程分数

解题思路与上题一致。

只需将上题的查询语句稍加改变即可,如下:

SELECT * FROM Student s Right Join

(SELECT r1.s_id, s1,s2 From

(SELECT s_id, s_score as s1 From score where c_id='01')r1,

(SELECT s_id, s_score as s2 From score where c_id='02')r2 

where r1.s_id=r2.s_id and s1<s2)R

On s.s_id=r.s_id;

结果集:


-- 3、查询平均成绩大于等于60分的同学的学生编号和学生姓名和平均成绩

分析思路:要使用AVG(),那么就要用到group by,结果要有学生姓名,那么需要用的join连接student表

方法一:子查询

#查询平均成绩大于等于60的学生编码和平均成绩

SELECT s_id,AVG(s_score) avs from score GROUP BY s_id HAVING avs>=60;

结果集

#把学生姓名加进来

SELECT s.s_id, s_name, r.avs from student s right join

(SELECT s_id,AVG(s_score) avs from score GROUP BY s_id HAVING avs>=60)r 

on s.s_id=r.s_id ;

结果集

方法二:不使用join语句

SELECT s.s_id, s_name, r.avs from student s ,

(SELECT s_id,AVG(s_score) avs from score GROUP BY s_id HAVING avs>=60)r 

where s.s_id=r.s_id ;

结果和上面一样。


-- 4、查询平均成绩小于60分的同学的学生编号和学生姓名和平均成绩(包括有成绩的和无成绩的)

分析思路:有成绩的且平均分小于60的学生和没有成绩的同学,分2部再连接在一起

#没成绩的学生编码,姓名和平均成绩(null)

SELECT s_id, s_name, null from student where s_id not in(SELECT DISTINCT s_id from score) ;  

结果集

#查询平均成绩低于60分的学生编码,姓名和平均成绩

SELECT r.s_id, s_name, r.avs from student s,

(SELECT s_id, ROUND(avg(s_score),2) avs from score 

GROUP BY s_id HAVING avs<60)r 

where s.s_id=r.s_id;

结果集

用了ROUND函数,使平均成绩保留2位小数。

#最后使用UNION合并到一起

SELECT r.s_id, s_name, r.avs from student s, (SELECT s_id,ROUND(avg(s_score),2) avs from score GROUP BY s_id HAVING avs<60)r where s.s_id=r.s_id

UNION

SELECT s_id,s_name,null from student where s_id not in(SELECT DISTINCT s_id from score)

最终结果集

-- 5、查询所有同学的学生编号、学生姓名、选课总数、所有课程的总成绩

分析思路:要用到COUNT(),SUM(), group by 分组,student表和score表,join连接,注意是所有学生,也就是包括没成绩的,所以要以student表为基准表

SELECT r.s_id, s.s_name, r.count_course, r.total_score from student s

LEFT JOIN

(SELECT s_id, count(*) as count_course, sum(s_score) as total_score from score GROUP BY s_id)r on s.s_id=r.s_id;

结果集

还有另一种写法:

select s.s_id, s.s_name, count(sc.c_id) as count_course, sum(sc.s_score) as sum_score from student s

left join score sc on s.s_id=sc.s_id  GROUP BY s.s_id, s.s_name;


-- 6、查询"李"姓老师的数量

分析思路:想到用LIKE,count()函数,teacher表

SELECT count(*) from teacher where t_name like "李%";

结果集

-- 7、查询学过"张三"老师授课的同学的信息

分析思路:4张表都要用到,需要从teacher先找到张三老师的编号,在course表中找到教的课程,在从score表找选修这门课程的学生编码,在连接student表查询出学生信息。

SELECT * from student where s_id in

(SELECT s_id from score where c_id=

(SELECT c_id from course where t_id=

(SELECT T_id from teacher where t_name='张三')))

这还真是一层一层的查(嵌套查询)

结果集

还有一种方法:(联合查询)

SELECT student.* from student where s_id in

(SELECT s_id from score sc,course c,teacher t

where sc.c_id=c.c_id

and c.t_id=t.t_id

and t_name='张三');

结果是一样的。


-- 8、查询没学过"张三"老师授课的同学的信息

分析思路:首先要知道张三老师教的哪门课程,然后逆向思维,先找到学过张三老师课程的学生,用not in找到没学过的学生信息

SELECT * from student where s_id not in

(SELECT s_id from score where c_id in

(SELECT c_id from course where t_id in

(SELECT t_id from teacher where t_name='张三')));

还有一种方法:

SELECT * from student where s_id not in

(SELECT s_id from score sc, course c, teacher t

where sc.c_id = c.c_id 

and c.t_id=t.t_id 

and t_name='张三')

相较第一种,第二种更简洁些。和7题相反,逻辑相似。


-- 9、查询学过编号为"01"并且也学过编号为"02"的课程的同学的信息

分析思路:分别查询学习2门课程的学生编号,再找到相同的,最后连接student表查询。

SELECT r.s_id,s_name,s_birth,s_sex from student

right join (SELECT s1.s_id from (SELECT s_id from score where c_id='01')s1

INNER JOIN (SELECT s_id from score where c_id='02')s2 on s1.s_id=s2.s_id)r

on student.s_id=r.s_id;

还有一种简洁的查询语句:

SELECT s.* from student s, score a, score b

where s.s_id = a.s_id  and s.s_id = b.s_id and a.c_id='01' and b.c_id='02';


-- 10、查询学过编号为"01"但是没有学过编号为"02"的课程的同学的信息

分析思路:查询学生编号在学习01课程的学生编号但不在学习02课程的编号里。

SELECT s.* from student s where s.s_id in

(SELECT s_id from score where c_id='01') 

and s.s_id not in (SELECT s_id from score where c_id='02');

结果集

以上10个题,其中1,3,4,8,9,10题很重要,也有些难度,需要搞清逻辑,当然方法不是唯一的,我相信还有其他解法的,学习sql一定要会做这几道题哦,大家相互参考,共同学习。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,463评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,868评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,213评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,666评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,759评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,725评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,716评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,484评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,928评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,233评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,393评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,073评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,718评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,308评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,538评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,338评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,260评论 2 352

推荐阅读更多精彩内容