MySQL SELECT查询语句练习2(中级篇)

导入现有数据库数据:

SET NAMES utf8;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
--  Table structure for `class`
-- ----------------------------
DROP TABLE IF EXISTS `class`;
CREATE TABLE `class` (
  `cid` int(11) NOT NULL AUTO_INCREMENT,
  `caption` varchar(32) NOT NULL,
  PRIMARY KEY (`cid`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

-- ----------------------------
--  Records of `class`
-- ----------------------------
BEGIN;
INSERT INTO `class` VALUES ('1', '三年二班'), ('2', '三年三班'), ('3', '一年二班'), ('4', '二年九班');
COMMIT;

-- ----------------------------
--  Table structure for `student`
-- ----------------------------
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
  `sid` int(11) NOT NULL AUTO_INCREMENT,
  `gender` char(1) NOT NULL,
  `class_id` int(11) NOT NULL,
  `sname` varchar(32) NOT NULL,
  PRIMARY KEY (`sid`),
  KEY `fk_class` (`class_id`),
  CONSTRAINT `fk_class` FOREIGN KEY (`class_id`) REFERENCES `class` (`cid`)
) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8;

-- ----------------------------
--  Records of `student`
-- ----------------------------
BEGIN;
INSERT INTO `student` VALUES ('1', '男', '1', '理解'), ('2', '女', '1', '钢蛋'), ('3', '男', '1', '张三'), ('4', '男', '1', '张一'), ('5', '女', '1', '张二'), ('6', '男', '1', '张四'), ('7', '女', '2', '铁锤'), ('8', '男', '2', '李三'), ('9', '男', '2', '李一'), ('10', '女', '2', '李二'), ('11', '男', '2', '李四'), ('12', '女', '3', '如花'), ('13', '男', '3', '刘三'), ('14', '男', '3', '刘一'), ('15', '女', '3', '刘二'), ('16', '男', '3', '刘四');
COMMIT;

-- ----------------------------
--  Table structure for `teacher`
-- ----------------------------
DROP TABLE IF EXISTS `teacher`;
CREATE TABLE `teacher` (
  `tid` int(11) NOT NULL AUTO_INCREMENT,
  `tname` varchar(32) NOT NULL,
  PRIMARY KEY (`tid`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

-- ----------------------------
--  Records of `teacher`
-- ----------------------------
BEGIN;
INSERT INTO `teacher` VALUES ('1', '张磊'), ('2', '李平'), ('3', '刘海燕'), ('4', '朱云海'), ('5', '李杰');
COMMIT;

-- ----------------------------
--  Table structure for `course`
-- ----------------------------
DROP TABLE IF EXISTS `course`;
CREATE TABLE `course` (
  `cid` int(11) NOT NULL AUTO_INCREMENT,
  `cname` varchar(32) NOT NULL,
  `teacher_id` int(11) NOT NULL,
  PRIMARY KEY (`cid`),
  KEY `fk_course_teacher` (`teacher_id`),
  CONSTRAINT `fk_course_teacher` FOREIGN KEY (`teacher_id`) REFERENCES `teacher` (`tid`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

-- ----------------------------
--  Records of `course`
-- ----------------------------
BEGIN;
INSERT INTO `course` VALUES ('1', '生物', '1'), ('2', '物理', '2'), ('3', '体育', '3'), ('4', '美术', '2');
COMMIT;

-- ----------------------------
--  Table structure for `score`
-- ----------------------------
DROP TABLE IF EXISTS `score`;
CREATE TABLE `score` (
  `sid` int(11) NOT NULL AUTO_INCREMENT,
  `student_id` int(11) NOT NULL,
  `course_id` int(11) NOT NULL,
  `num` int(11) NOT NULL,
  PRIMARY KEY (`sid`),
  KEY `fk_score_student` (`student_id`),
  KEY `fk_score_course` (`course_id`),
  CONSTRAINT `fk_score_course` FOREIGN KEY (`course_id`) REFERENCES `course` (`cid`),
  CONSTRAINT `fk_score_student` FOREIGN KEY (`student_id`) REFERENCES `student` (`sid`)
) ENGINE=InnoDB AUTO_INCREMENT=53 DEFAULT CHARSET=utf8;

-- ----------------------------
--  Records of `score`
-- ----------------------------
BEGIN;
INSERT INTO `score` VALUES ('1', '1', '1', '10'), ('2', '1', '2', '9'), ('5', '1', '4', '66'), ('6', '2', '1', '8'), ('8', '2', '3', '68'), ('9', '2', '4', '99'), ('10', '3', '1', '77'), ('11', '3', '2', '66'), ('12', '3', '3', '87'), ('13', '3', '4', '99'), ('14', '4', '1', '79'), ('15', '4', '2', '11'), ('16', '4', '3', '67'), ('17', '4', '4', '100'), ('18', '5', '1', '79'), ('19', '5', '2', '11'), ('20', '5', '3', '67'), ('21', '5', '4', '100'), ('22', '6', '1', '9'), ('23', '6', '2', '100'), ('24', '6', '3', '67'), ('25', '6', '4', '100'), ('26', '7', '1', '9'), ('27', '7', '2', '100'), ('28', '7', '3', '67'), ('29', '7', '4', '88'), ('30', '8', '1', '9'), ('31', '8', '2', '100'), ('32', '8', '3', '67'), ('33', '8', '4', '88'), ('34', '9', '1', '91'), ('35', '9', '3', '67'), ('36', '9', '4', '22'), ('37', '10', '1', '90'), ('38', '10', '2', '77'), ('39', '10', '3', '43'), ('40', '10', '4', '87'), ('41', '11', '1', '90'), ('42', '11', '2', '77'), ('43', '11', '3', '43'), ('44', '11', '4', '87'), ('45', '12', '1', '90'), ('46', '12', '2', '77'), ('47', '12', '3', '43'), ('48', '12', '4', '87'), ('49', '13', '3', '87');
COMMIT;

1、查询“生物”课程比“物理”课程成绩高的所有学生的学号;

思路:
    获取所有有生物课程的人(学号,成绩) - 临时表
    获取所有有物理课程的人(学号,成绩) - 临时表
    根据【学号】连接两个临时表:
    学号 | 物理成绩 | 生物成绩
    然后再进行筛选
SELECT A.student_id, sw, wl FROM
( SELECT student_id, num AS sw FROM score LEFT JOIN course ON score.course_id = course.cid WHERE course.cname = "生物" ) AS A
LEFT JOIN 
( SELECT student_id, num AS wl FROM score LEFT JOIN course ON score.course_id = course.cid WHERE course.cname = "物理" ) AS B 
ON A.student_id = B.student_id WHERE A.sw >IF(ISNULL(B.wl), 0, B.wl );

注:
1.if()用法:if(条件,条件成立的返回值,条件不成立的返回值)
2.此题若先检索“物理”左联“生物”,结果会缺少“物理=0”的情况,体会左联和右联区别
3.LEFT JOIN……ON 后面加AND表示满足前后两个条件都可联结,取二者并集;后面加WHERE表示对联结后的结果进行筛选,可参考https://www.cnblogs.com/caoyajun33-blog/p/6814185.html

2、查询平均成绩大于60分的同学的学号和平均成绩;

#根据学生分组,使用avg获取平均值,通过having对avg进行筛选

select student_id,avg(num) from score group by student_id having avg(num)>60;

3、查询所有同学的学号、姓名、选课数、总成绩;

select sc.student_id,s.sname,count(sc.course_id),sum(sc.num) 
from student as s left join score as sc on s.sid=sc.student_id
group by sc.student_id 
order by sum(sc.num) desc;

4、查询姓“李”的老师的个数;

select count(1) from teacher where tname like '李%';

5、查询没学过“李平老师”课的同学的学号、姓名;

select sid,sname from student where sid not in (
	select distinct student_id from score where course_id in(
		select cid from course where teacher_id=
			(select tid from teacher where tname='李平'
				)
		) 
);

6、查询学过编号“1”并且也学过编号“2”课程的同学的学号、姓名;

思路:
    先查到既选择1又选择2课程的所有同学
    根据学生进行分组,如果学生数量等于2表示两门均已选择
#左联        
select sid,sname from student 
left join 
(select student_id from score where course_id=1 or course_id=2) as b
on student.sid=b.student_id
group by student_id having count(student_id)>1;

select sc.student_id,s.sname from score as sc 
left join student as s on sc.student_id=s.sid
where sc.student_id in
(select student_id from score where course_id=1 or course_id=2)
group by sc.student_id
having count(1)>1;

#子查询
SELECT sid,sname FROM student WHERE sid IN 
	(
		SELECT student_id FROM score WHERE course_id = 1 OR course_id = 2
		GROUP BY student_id HAVING count(course_id) = 2
	)
	
注:【wherehaving的区别】

1.where后面不能接聚合函数(count()sum()max()min()avg())。
  所以上述子查询中不能用
  GROUP BY student_id HAVING course_id=1 OR course_id=2 WHERE count(student_id)=2
  因此一般的顺序是WHERE……GROUP BY……HAVING	
  
2.having是从已经筛选的字段中再筛选,而where是从数据表中的字段直接进行的筛选的。

(1wherehaving都能用的情景
	select price,name from goods where price > 100select price,name from goods having price > 100 √
	说明:前面已经有了select price字段,因此用having也可以。
	
(2)只能用where,不能用having的情景
	select name from goods where price >100select name from goods having price >100 x 
	说明:因为select没有筛选出price,所以不能再用having二次筛选
	
(3)只能用having,不能用where的情景
	select id, avg(price) as agprice from goods group by id having agprice > 100
	select id, avg(price) as agprice from goods where agprice>100 group by id 
	说明:因为goods表里面没有agprice这个字段,所以用where会报错;而根据第1where不能接聚合函数,可知用where avg(price)也不行,所以只能用having

7、查询学过“李平老师”所教的所有课的同学的学号、姓名;

select sid,sname from student where sid in
	(select student_id from score where course_id in
		(select cid from course where teacher_id in 
			(select tid from teacher where tname='李平'
			)
		)
	);

8、查询课程编号“2”的成绩比课程编号“1”课程低的所有同学的学号、姓名;

#方法1:
select sid,sname,a.high,b.low from student as s
left join
(select student_id,num as high from score where course_id=1 ) as a
on s.sid=a.student_id
left join 
(select student_id,num as low from score where course_id=2 ) as b
on a.student_id=b.student_id 
where a.high>if(isnull(b.low),0,b.low);

#方法2:
SELECT
	a.sid,
	a.sname,
	c_1_num,
	c_2_num
FROM
	(
		SELECT
			s.sid,
			s.sname,
			sc.num AS c_1_num
		FROM
			student AS s
		LEFT JOIN score AS sc ON s.sid = sc.student_id
		WHERE
			sc.course_id = 1
	) AS a
LEFT JOIN
	(
		SELECT
			s.sid,
			s.sname,
			sc.num AS c_2_num
		FROM
			student AS s
		LEFT JOIN score AS sc ON s.sid = sc.student_id
		WHERE
			sc.course_id = 2
	) AS b 
ON a.sid = b.sid
WHERE
	c_1_num >
IF (ISNULL(c_2_num), 0, c_2_num);

9、查询有课程成绩小于60分的同学的学号、姓名;

方法1:连接
	select distinct sid,sname from student 
	inner join (select student_id,num from score where num<60) as a
	on student.sid=a.student_id;

方法2:子查询
	select sid,sname from student where sid in(
		select student_id from score where num<60
	);

10、查询没有学全所有课的同学的学号、姓名;

#情况1:0<学的课数<所有课(子查询)
select distinct sid,sname from student where sid in(
	select student_id from score 
	group by student_id 
	having count(course_id)<(select count(cid) from course)
);

#情况1:0<学的课数<所有课(连接)
select student_id,sname from score 
left join student on score.student_id = student.sid
group by student_id HAVING count(course_id) <(select count(1) from course);

#情况2:0<=学的课数<所有课
select s.sid,s.sname from student s
left join score on s.sid=score.student_id
group by s.sid having count(course_id)<(select count(cid) from course);

体会"左联"的顺序对结果的影响

11、查询至少有一门课与学号为“1 ”的同学所学相同的同学的学号和姓名;

方法1:子查询
select sid,sname from student where sid in (
	select distinct student_id from score  where student_id !=1 and 
	course_id in (
		select course_id from score  where student_id=1 
		)
	);

方法2:连接	
SELECT DISTINCT
	student_id,
	sname
FROM
	student,
	score
WHERE
	score.student_id = student.sid
AND student_id <> 1
AND course_id IN (
	SELECT
		course_id
	FROM
		score
	WHERE
		student_id = 1
);

12、查询至少学过学号为“1”同学所有课的其他同学学号和姓名;

select sid,sname from student where sid<>1 and sid in (
    #子查询+where筛选和学号1上课有交集的同学,1上3门课,所以课程门数交集数量可能是1或2或3
    select student_id from score where course_id in (
        select course_id from score where student_id=1
        ) 
    group by student_id 
    #having过滤掉上课门数小于1的同学,此处的>=也可用=
    having count(course_id)>=(select count(course_id) from score where student_id=1)
);
	#数据举例:同学2上三门课,where筛选后2与1有交集的是两门,having再次筛选,筛选后的课程数是2,小于1上的三门课,所以2被淘汰

13、查询和“2”号的同学学习的课程完全相同的其他同学学号和姓名;

SELECT
	sid,
	sname
FROM
	student
WHERE
	sid <> 2
AND sid NOT IN ( #排除学习了这些选修课的学生,剩下的学生选修的课2都学习了
	SELECT
		student_id
	FROM
		score
	WHERE
	#排除2不学的选修课
		course_id NOT IN (
			SELECT
				course_id
			FROM
				score
			WHERE
				student_id = 2
		)
)
AND sid IN ( 	#与2号选修科目数量相等的同学
	SELECT
		student_id
	FROM
		score
	GROUP BY
		student_id
	HAVING
		count(*) = (
			SELECT
				count(course_id)
			FROM
				score
			WHERE
				student_id = 2
		)
);

14、按平均成绩从低到高显示所有学生的“生物”、“物理”、“体育”、“美术”四门的课程成绩,按如下形式显示: 学生ID,生物,物理,体育,美术,有效课程数,有效平均分

#方法1:左联+临时表
select sc.student_id as '学生ID',
(select num from score left join course on score.course_id=course.cid where cname='生物' and sc.student_id=score.student_id) as '生物',
(select num from score left join course on score.course_id=course.cid where cname='物理' and sc.student_id=score.student_id) as '物理',
(select num from score left join course on score.course_id=course.cid where cname='体育' and sc.student_id=score.student_id) as '体育',
(select num from score left join course on score.course_id=course.cid where cname='美术' and sc.student_id=score.student_id) as '美术',
count(sc.course_id) as '课程数',
avg(sc.num) as '平均分'
from score as sc 
group by sc.student_id
order by avg(sc.num) ;

#方法2:子查询+临时表
select sc.student_id,
(select num from score where score.student_id=sc.student_id and course_id=(select cid from course where cname='生物'))as '生物',
(select num from score where score.student_id=sc.student_id and course_id=(select cid from course where cname='物理'))as '物理',
(select num from score where score.student_id=sc.student_id and course_id=(select cid from course where cname='体育'))as '体育',
(select num from score where score.student_id=sc.student_id and course_id=(select cid from course where cname='美术'))as '美术',
count(sc.course_id) as '课程数',
avg(sc.num) as '平均分'
from score as sc
group by sc.student_id
order by avg(sc.num) ;

方法3:左联+临时表
select sc.student_id as "学生ID",sw as "生物",wl as "物理",ty as "体育",ms as "美术",count(course_id) as "有效课程数",avg(num) as "有效平均分" from score as sc
left join 
(select student_id,num as sw from score left join course as c on score.course_id=c.cid WHERE c.cname="生物") as SW ON sc.student_id=SW.student_id
left join 
(select student_id,num as wl from score left join course as c on score.course_id=c.cid WHERE c.cname="物理") as WL ON sc.student_id=WL.student_id
left join 
(select student_id,num as ty from score left join course as c on score.course_id=c.cid WHERE c.cname="体育") as TY ON sc.student_id=TY.student_id
left join 
(select student_id,num as ms from score left join course as c on score.course_id=c.cid WHERE c.cname="美术") as MS ON sc.student_id=MS.student_id
GROUP BY 学生ID
ORDER BY 有效平均分;

注:
1.GROUP BYORDER BY时可以直接用别名;
2.主查询可直接使用临时表中查询的别名

15、查询各科成绩最高和最低的分:以如下形式显示:课程ID,最高分,最低分;

select sc.course_id as '课程ID',
(select max(num) from score where score.course_id=sc.course_id) as '最高分',
(select min(num) from score where score.course_id=sc.course_id) as '最低分'
from score as sc
group by course_id;

select a.course_id,max_num,min_num from
(select course_id,max(num) as max_num from score group by course_id) as a
left join 
(select course_id,min(num) as min_num from score group by course_id) as b
on a.course_id=b.course_id;

16、按各科平均成绩从低到高和及格率的百分数从高到低顺序;

select c.cname,
round((select avg(num) from score where c.cid=course_id),0) as av,
CONCAT(round((select count(student_id) from score where num > av and c.cid=score.course_id)/(select count(student_id) from score where c.cid=score.course_id)*100,0),'%') as pass_rate
from course as c
group by c.cname
order by av,pass_rate desc

select sc.course_id,avg(num),pass_rate from 
(select course_id,sum(if(num>60,1,0))/count(student_id) as pass_rate from score group by course_id) as a
left join score as sc on sc.course_id=a.course_id
group by course_id
order by avg(num) asc,pass_rate desc;

17、课程平均分从高到低显示(显示任课老师);

select c.cname,avg(sc.num),t.tname from score sc
left join course c on sc.course_id=c.cid
left join teacher t on c.teacher_id=t.tid
group by c.cname
order by avg(sc.num) desc;

select cname,tname,avg(num) from course,teacher,score
where cid=course_id and teacher_id=tid
group by cname
order by avg(num) desc;

18、查询各科成绩前三名的记录:(不考虑成绩并列情况)

思路:先找到各科排名第一和第三的分数,分数在这一闭合区间内则为前三名
select distinct num,course_id from score as sc 
where num<=
(select distinct num from score where score.course_id=sc.course_id order by num desc limit 0,1)
and num>=
(select distinct num from score where score.course_id=sc.course_id order by num desc limit 2,1)
order by course_id,num desc;

19、查询每门课程被选修的学生数;

select course_id,count(student_id) from score
group by course_id;

20、查询出只选修了一门课程的全部学生的学号和姓名;

SELECT
	score.student_id,
	student.sname 
FROM
	score
	LEFT JOIN student ON score.student_id = student.sid 
GROUP BY
	score.student_id 
HAVING
	count( course_id ) = 1;
	
select sid,sname from student where sid in
(select student_id from score group by student_id having count(course_id)=1)

21、查询男生、女生的人数;

select gender,count(*) from student group by gender

22、查询姓“张”的学生名单;

select * from student where sname like '张%';

23、查询同名同姓学生名单,并统计同名人数;

select sname,count(*) from student as s where sname=
(select sname from student where student.sid<>s.sid and student.sname=s.sname);

select * ,count(sname) from student
group by sname 
having count(sname)>1

24、查询每门课程的平均成绩,结果按平均成绩升序排列,平均成绩相同时,按课程号降序排列;

select course_id,avg(num) from score group by course_id order by avg(num),course_id desc;

25、查询平均成绩大于85的所有学生的学号、姓名和平均成绩;

select s.sid,s.sname,avg(num) from student as s
left join score as sc on s.sid=sc.student_id
group by s.sid having avg(sc.num)>85;

26、查询课程名称为“物理”,且分数低于60的学生姓名和分数;

select c.cname,s.sname,sc.num from course as c
left join score as sc on sc.course_id=c.cid
left join student as s on sc.student_id=s.sid
where c.cname='物理' and sc.num<60;

27、查询课程编号为003且课程成绩在80分以上的学生的学号和姓名;

select sc.course_id,sc.num,s.sid,s.sname from score as sc
left join student as s on sc.student_id=s.sid
where sc.course_id=3 and sc.num>80;

28、求选了课程的学生人数

select count(distinct student_id) from score;

29、查询选修“李平老师”所授课程的学生中,成绩最高的学生姓名及其成绩;

select sc.course_id,s.sname,sc.num from student as s
left join score as sc on sc.student_id=s.sid
left join course as c on sc.course_id=c.cid
left join teacher as t on c.teacher_id=t.tid
where t.tname='李平' and sc.num>=all
(
	select num from score where course_id=sc.course_id
);

30、查询各个课程及相应的选修人数;

select c.cid,c.cname,count(sc.student_id) from course as c
left join score as sc on c.cid=sc.course_id
group by sc.course_id;

31、查询不同课程但成绩相同的学生的学号、课程号、学生成绩;

select a.student_id,a.course_id,a.num from score a 
left join score b on a.student_id=b.student_id
where a.course_id<>b.course_id
and a.num=b.num;

select student_id,course_id,num from score a where student_id in 
	(select student_id from score b where a.course_id<>b.course_id and a.num=b.num
	)

32、查询每门课程成绩最好的前两名;




33、检索至少选修两门课程的学生学号;

select student_id,count(course_id) as number from score group by student_id having number>=2

34、查询全部学生都选修的课程的课程号和课程名;

思路:先确认全部学生人数;基于课程ID分组后,选该课的人数等于全部学生人数
select sc.course_id,c.cname from score as sc
left join course as c on sc.course_id=c.cid
group by course_id 
having count(*)=(
	select count(distinct student_id) from score
)

select course_id,cname from score,course
where course_id=cid
group by course_id 
having count(*)=(select count(distinct student_id) from score)

35、查询没学过“李平老师”讲授的任一门课程的学生姓名;

select sid,sname from student where sid not in(
	select student_id from score where course_id in(
		select cid from course where teacher_id =(
			select tid from teacher where tname='李平'
		)
	)
)

36、查询两门及以上不及格课程的同学的学号及其平均成绩;

SELECT student_id,avg(num) FROM score WHERE student_id IN 
(
		SELECT student_id FROM score WHERE num < 60 
		GROUP BY student_id HAVING count(*) > 1
)
GROUP BY student_id;

37、检索课程“1”分数小于60,按分数降序排列的同学学号;

select student_id,num from score 
where course_id=1 and num<60
order by num desc;
发布了6 篇原创文章 · 获赞 2 · 访问量 1917

猜你喜欢

转载自blog.csdn.net/weixin_44361892/article/details/91362897