数据库04: 多表查询
Posted fqh202
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据库04: 多表查询相关的知识,希望对你有一定的参考价值。
多表连接查询
准备表
# 部门表
create table dept(
id int primary key not null auto_increment,
name varchar(20) not null
);
# 员工信息表
create table employee(
id int primary key auto_increment,
name varchar(20) not null,
sex enum('male','female') not null default 'male',
age int not null ,
dept_id int not null,
foreign key(dept_id) references dept(id)
on delete cascade
on update cascade
);
# 插入数据
insert into dept(name) values
('技术'),
('人力资源'),
('销售'),
('运营');
insert into employee(name,sex,age,dept_id) values
('kate','male',18,1),
('alex','female',48,2),
('bob','male',38,3),
('shanshan','female',28,4),
('jim','male',18,1),
('dereck','female',18,3)
;
SELECT 字段列表
FROM 表1 INNER|LEFT|RIGHT JOIN 表2
ON 表1.字段 = 表2.字段;
交叉连接(可忽略)
不适用任何匹配条件。生成笛卡尔积,结果没有任何参考作用.
select * from dept, employee;
+----+------------+--------+------+--------+------+--------------+
| id | name | sex | age | dep_id | id | name |
+----+------------+--------+------+--------+------+--------------+
| 1 | egon | male | 18 | 200 | 200 | 技术 |
| 1 | egon | male | 18 | 200 | 201 | 人力资源 |
| 1 | egon | male | 18 | 200 | 202 | 销售 |
| 1 | egon | male | 18 | 200 | 203 | 运营 |
| 2 | alex | female | 48 | 201 | 200 | 技术 |
| 2 | alex | female | 48 | 201 | 201 | 人力资源 |
| 2 | alex | female | 48 | 201 | 202 | 销售 |
| 2 | alex | female | 48 | 201 | 203 | 运营 |
| 3 | wupeiqi | male | 38 | 201 | 200 | 技术 |
| 3 | wupeiqi | male | 38 | 201 | 201 | 人力资源 |
| 3 | wupeiqi | male | 38 | 201 | 202 | 销售 |
| 3 | wupeiqi | male | 38 | 201 | 203 | 运营 |
| 4 | yuanhao | female | 28 | 202 | 200 | 技术 |
| 4 | yuanhao | female | 28 | 202 | 201 | 人力资源 |
| 4 | yuanhao | female | 28 | 202 | 202 | 销售 |
| 4 | yuanhao | female | 28 | 202 | 203 | 运营 |
| 5 | liwenzhou | male | 18 | 200 | 200 | 技术 |
| 5 | liwenzhou | male | 18 | 200 | 201 | 人力资源 |
| 5 | liwenzhou | male | 18 | 200 | 202 | 销售 |
| 5 | liwenzhou | male | 18 | 200 | 203 | 运营 |
| 6 | jingliyang | female | 18 | 204 | 200 | 技术 |
| 6 | jingliyang | female | 18 | 204 | 201 | 人力资源 |
| 6 | jingliyang | female | 18 | 204 | 202 | 销售 |
| 6 | jingliyang | female | 18 | 204 | 203 | 运营 |
+----+------------+--------+------+--------+------+--------------+
内连接
inner join
: 按照where
筛选出表之间共有的部分,相当于利用条件从笛卡尔积结果中筛选出了正确的结果;
若dept
表中没有dept_num
部门,所以employee
表中关于dept_num
这条员工信息都不会匹配出来;
# 常规方法
select employee.id,employee.name,employee.age,employee.sex,department.name
from employee,department where employee.dep_id=department.id;
# inner join
select employee.id,employee.name,employee.age,employee.sex,dept.name
from employee inner join dept on employee.dep_id=dept.id;
+----+-----------+------+--------+--------------+
| id | name | age | sex | name |
+----+-----------+------+--------+--------------+
| 1 | egon | 18 | male | 技术 |
| 2 | alex | 48 | female | 人力资源 |
| 3 | wupeiqi | 38 | male | 人力资源 |
| 4 | yuanhao | 28 | female | 销售 |
| 5 | liwenzhou | 18 | male | 技术 |
+----+-----------+------+--------+--------------+
外连接之左连接
优先显示左表全部记录;
以左表为准,即找出所有员工信息,包括没有部门的员工;
本质就是:在内连接的基础上增加左边有右边没有的结果;
select employee.id,employee.name,department.name as depart_name
from employee left join department
on employee.dep_id=department.id;
+----+------------+--------------+
| id | name | depart_name |
+----+------------+--------------+
| 1 | egon | 技术 |
| 5 | liwenzhou | 技术 |
| 2 | alex | 人力资源 |
| 3 | wupeiqi | 人力资源 |
| 4 | yuanhao | 销售 |
| 6 | jingliyang | NULL |
外链接之右连接
优先显示右表全部记录;
以右表为准,即找出所有部门信息,包括没有员工的部门;
本质就是:在内连接的基础上增加右边有左边没有的结果;
select employee.id,employee.name,dept.name as dept_name
from employee right join dept
on employee.dept_id=dept.id;
+------+-----------+--------------+
| id | name | depart_name |
+------+-----------+--------------+
| 1 | egon | 技术 |
| 2 | alex | 人力资源 |
| 3 | wupeiqi | 人力资源 |
| 4 | yuanhao | 销售 |
| 5 | liwenzhou | 技术 |
| NULL | NULL | 运营 |
+------+-----------+--------------+
全外连接
显示左右两个表全部记录
全外连接:在内连接的基础上增加左边有右边没有的和右边有左边没有的结果
注意:mysql不支持全外连接 full JOIN
强调:mysql可以使用此种方式间接实现全外连接
select * from employee left join dept on employee.dept_id = dept.id
union
select * from employee right join dept on employee.dep_id = dept.id
;
#查看结果
# 也包括没有员工的部门或不属于已知部门的员工;
mysql> select * from employee left join dept on employee.dept_id = dept.id union select * from employee right join dept on employee.dept_id = dept.id ;
+------+------------+--------+------+---------+------+----------+
| id | name | sex | age | dept_id | id | name |
+------+------------+--------+------+---------+------+----------+
| 1 | egon | male | 18 | 1 | 1 | 技术 |
| 5 | liwenzhou | male | 18 | 1 | 1 | 技术 |
| 2 | alex | female | 48 | 2 | 2 | 人力资源 |
| 3 | wupeiqi | male | 38 | 3 | 3 | 销售 |
| 6 | jingliyang | female | 18 | 3 | 3 | 销售 |
| 4 | yuanhao | female | 28 | 4 | 4 | 运营 |
| NULL | NULL | NULL | NULL | NULL | 5 | 支持 |
+------+------------+--------+------+---------+------+----------+
7 rows in set (0.00 sec)
条件连接查询
示例1:以内连接的方式查询employee
和dept
表,并且employee表中的age
字段值必须大于25
,即找出年龄大于25岁的员工以及员工所在的部门.
select employee.id, employee.name as "员工", employee.age, dept.name as '部门' from employee right join dept
on employee.dept_id = dept.id
where age > 25 order by age;
+------+---------+------+----------+
| id | 员工 | age | 部门 |
+------+---------+------+----------+
| 2 | alex | 48 | 人力资源 |
| 3 | wupeiqi | 38 | 销售 |
| 4 | yuanhao | 28 | 运营 |
+------+---------+------+----------+
3 rows in set (0.00 sec)
子查询
主要确定主要字段和中间字段.
- 子查询是将一个查询语句嵌套在另一个查询语句中;
- 内层查询语句的查询结果,可以为外层查询语句提供查询条件;
- 子查询中可以包含:
IN
、NOT IN
、ANY
、ALL
、EXISTS
和NOT EXISTS
等关键字; - 还可以包含比较运算符:
=
,!=
,>
,<
等;
IN
# 查询 平均年龄 在25岁以上的 部门名
select id,name from dept
where id in
(select dept_id from emp group by dept_id
having avg(age) > 25);
# 查看 技术部 员工姓名
select name, dept_id from employee
where dept_id in
(select id from dept where name ='技术');
# 查看 不足1人 的部门名
select name from dept where id in (select dept_id as dept_num from emp group by dept_id having count(id) <=1);
+----------+
| name |
+----------+
| 人力资源 |
| 运营 |
+----------+
2 rows in set (0.00 sec)
比较运算符
# 查询大于 所有人 平均年龄 的 员工的姓名与年龄
mysql> select name, age from emp where age>(select avg(age) from emp);
+---------+-----+
| name | age |
+---------+-----+
| alex | 48 |
| wupeiqi | 38 |
+---------+-----+
2 rows in set (0.00 sec)
# 查询大于 部门 内平均年龄的员工姓名、年龄
# 1. 新建dept_id, avg_age的中间表;
# 2. 将其连接employee表, 筛选出age和avg_age字段;
select t1.name,t1.age from employee t1
inner join
(select dept_id,avg(age) as avg_age from employee group by dept_id) t2
on t1.dept_id = t2.dept_id
where t1.age >= t2.avg_age;
+---------+-----+
| name | age |
+---------+-----+
| alex | 48 |
| wupeiqi | 38 |
| yuanhao | 28 |
| jim1 | 29 |
| jack | 40 |
+---------+-----+
5 rows in set (0.00 sec)
EXISTS
EXISTS
关字键字表示存在。在使用EXISTS关键字时,内层查询语句不返回查询的记录;
返回一个真假值:True
或False
;
当返回True
时,外层查询语句将进行查询;当返回值为False
时,外层查询语句不进行查询;
# department表中存在dept_id=203,Ture
select * from employee where exists
(select id from dept where id=200);
+----+------------+--------+------+--------+
| id | name | sex | age | dep_id |
+----+------------+--------+------+--------+
| 1 | egon | male | 18 | 200 |
| 2 | alex | female | 48 | 201 |
| 3 | wupeiqi | male | 38 | 201 |
| 4 | yuanhao | female | 28 | 202 |
| 5 | liwenzhou | male | 18 | 200 |
| 6 | jingliyang | female | 18 | 204 |
+----+------------+--------+------+--------+
# department表中存在dept_id=205,False
select * from employee
where exists
(select id from department where id=204);
Empty set (0.00 sec)
子查询练习
# 创建表
create table employee(
id int not null unique auto_increment,
name varchar(20) not null,
sex enum('male','female') not null default 'male', #大部分是男的
age int(3) unsigned not null default 28,
hire_date date not null,
post varchar(50),
post_comment varchar(100),
salary double(15,2),
office int, #一个部门一个屋子
depart_id int
);
# 插入记录
# 三个部门:教学,销售,运营
insert into employee(name,sex,age,hire_date,post,salary,office,depart_id) values
('egon','male',18,'20170301','老男孩驻沙河办事处外交大使',7300.33,401,1), #以下是教学部
('alex','male',78,'20150302','teacher',1000000.31,401,1),
('wupeiqi','male',81,'20130305','teacher',8300,401,1),
('yuanhao','male',73,'20140701','teacher',3500,401,1),
('liwenzhou','male',28,'20121101','teacher',2100,401,1),
('jingliyang','female',18,'20110211','teacher',9000,401,1),
('jinxin','male',18,'19000301','teacher',30000,401,1),
('成龙','male',48,'20101111','teacher',10000,401,1),
('歪歪','female',48,'20150311','sale',3000.13,402,2),#以下是销售部门
('丫丫','female',38,'20101101','sale',2000.35,402,2),
('丁丁','female',18,'20110312','sale',1000.37,402,2),
('星星','female',18,'20160513','sale',3000.29,402,2),
('格格','female',28,'20170127','sale',4000.33,402,2),
('张野','male',28,'20160311','operation',10000.13,403,3), #以下是运营部门
('程咬金','male',18,'19970312','operation',20000,403,3),
('程咬银','female',18,'20130311','operation',19000,403,3),
('程咬铜','male',18,'20150411','operation',18000,403,3),
('程咬铁','female',18,'20140512','operation',17000,403,3)
;
# 题目: 查询每个部门 最新入职的那位 员工
# 方法1=========================================================
# 1. 建立中间表t1, 包括depart_id 和 max_hire_date
# 2. 连表, 筛选记录中hire_date与max_hire_date相等即可
select t1.name, t1.age, t1.depart_id from employee t1
inner join
(select depart_id,max(hire_date) as recent_date from employee group by depart_id) t2
on t1.depart_id=t2.depart_id where hire_date=recent_date;
+------+-----+-----------+
| name | age | depart_id |
+------+-----+-----------+
| egon | 18 | 1 |
| 格格 | 28 | 2 |
| 张野 | 28 | 3 |
+------+-----+-----------+
3 rows in set (0.00 sec)
sql注入
准备文件
init.sql
,内容如下:/* 数据导入: Navicat Premium Data Transfer Source Server : localhost Source Server Type : MySQL Source Server Version : 50624 Source Host : localhost Source Database : sqlexam Target Server Type : MySQL Target Server Version : 50624 File Encoding : utf8 Date: 10/21/2016 06:46:46 AM */ 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 `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', '2', '88'), ('36', '9', '3', '67'), ('37', '9', '4', '22'), ('38', '10', '1', '90'), ('39', '10', '2', '77'), ('40', '10', '3', '43'), ('41', '10', '4', '87'), ('42', '11', '1', '90'), ('43', '11', '2', '77'), ('44', '11', '3', '43'), ('45', '11', '4', '87'), ('46', '12', '1', '90'), ('47', '12', '2', '77'), ('48', '12', '3', '43'), ('49', '12', '4', '87'), ('52', '13', '3', '87'); 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; SET FOREIGN_KEY_CHECKS = 1;
连接上数据库,开始注入:
mysql> create database db1; mysql> use db1; mysql> source /root/init.sql
在
window
上容易出现中文乱码,终极解决办法:# init.sql [mysqld] default-character-set=utf8 [client] default-character-set=utf8 [mysql] default-character-set=utf8
练习题目
1. 查询所有的课程的名称以及对应的任课老师姓名
# 步骤:仅仅根据相关条件连接两个表格即可
mysql> select course.cname, teacher.tname from course left join teacher
-> on course.teacher_id=teacher.tid;
+-------+------------+
| cname | tname |
+-------+------------+
| 生物 | 张磊老师 |
| 物理 | 李平老师 |
| 体育 | 刘海燕老师 |
| 美术 | 李平老师 |
+-------+------------+
4 rows in set (0.00 sec)
2、查询学生表中男女生各有多少人
# 步骤:进行group by分组即可
mysql> select gender, count(sid) from student group by gender;
+--------+------------+
| gender | count(sid) |
+--------+------------+
| 女 | 6 |
| 男 | 10 |
+--------+------------+
2 rows in set (0.00 sec)
3、查询物理成绩等于100的学生的姓名
# 方法1:子查询----------------------
# 步骤1:先筛选出物理成绩等于100的学生id;
mysql> select student_id from score where course_id = (select cid from course where cname='物理') and num=100;
+------------+
| student_id |
+------------+
| 6 |
| 7 |
| 8 |
+------------+
3 rows in set (0.00 sec)
# 步骤2:从学生表中根据id查询出对应的学生姓名
mysql> select sname from student where sid in (select student_id from score where course_id = (select cid from course where cname='物理') and num=100);
+-------+
| sname |
+-------+
| 张四 |
| 铁锤 |
| 李三 |
+-------+
3 rows in set (0.00 sec)
# 方法二、连表查询------------------
# 将student表和符合条件的id表连接起来,取出相应的字段即可
mysql> select sname from student inner join
(select student_id from score where course_id = (select cid from course where cname='物理') and
num=100) as a
-> on a.student_id=student.sid;
+-------+
| sname |
+-------+
| 张四 |
| 铁锤 |
| 李三 |
+-------+
3 rows in set (0.00 sec)
4、查询平均成绩大于八十分的同学的姓名和平均成绩
# 1 找出平均分数大于80的同学的id, 注意为新字段添加名称,方便后续利用
mysql> select student_id, avg(num) as avg_num from score group by student_id having avg(num)>80 ;
+------------+---------+
| student_id | avg_num |
+------------+---------+
| 3 | 82.2500 |
| 13 | 87.0000 |
+------------+---------+
2 rows in set (0.00 sec)
# 2 将学生表和之前产生的虚拟表连接起来
mysql> select student.sname, a.avg_num from student inner join (select student_id, avg(num) as avg_num from score group by student_id having avg(num)>80) as a on a.student_id=student.sid;
+-------+---------+
| sname | avg_num |
+-------+---------+
| 张三 | 82.2500 |
| 刘三 | 87.0000 |
+-------+---------+
2 rows in set (0.00 sec)
5、查询所有学生的学号,姓名,选课数,总成绩
# 步骤1: 产生虚拟列表学生id,总成绩,选课数
mysql> select student_id, sum(num) as total_score, count(course_id) as course_count from score group by student_id;
+------------+-------------+--------------+
| student_id | total_score | course_count |
+------------+-------------+--------------+
| 1 | 85 | 3 |
| 2 | 175 | 3 |
| 3 | 329 | 4 |
| 4 | 257 | 4 |
| 5 | 257 | 4 |
| 6 | 276 | 4 |
| 7 | 264 | 4 |
| 8 | 264 | 4 |
| 9 | 268 | 4 |
| 10 | 297 | 4 |
| 11 | 297 | 4 |
| 12 | 297 | 4 |
| 13 | 87 | 1 |
+------------+-------------+--------------+
13 rows in set (0.00 sec)、
# 步骤2: 内连接, 根据需求取出相应的字段
mysql> select student.sid, student.sname, a.course_count, a.total_score from student inner join (select student_id, sum(num) as total_score, count(course_id) as course_count from score group by student_id) as a on a.student_id=student.sid;
+-----+-------+--------------+-------------+
| sid | sname | course_count | total_score |
+-----+-------+--------------+-------------+
| 1 | 理解 | 3 | 85 |
| 2 | 钢蛋 | 3 | 175 |
| 3 | 张三 | 4 | 329 |
| 4 | 张一 | 4 | 257 |
| 5 | 张二 | 4 | 257 |
| 6 | 张四 | 4 | 276 |
| 7 | 铁锤 | 4 | 264 |
| 8 | 李三 | 4 | 264 |
| 9 | 李一 | 4 | 268 |
| 10 | 李二 | 4 | 297 |
| 11 | 李四 | 4 | 297 |
| 12 | 如花 | 4 | 297 |
| 13 | 刘三 | 1 | 87 |
+-----+-------+--------------+-------------+
13 rows in set (0.00 sec)
6、 查询姓李老师的个数
mysql> select count(tname) as '姓李的老师数目' from teacher where tname like "李%";
+----------------+
| 姓李的老师数目 |
+----------------+
| 2 |
+----------------+
1 row in set (0.00 sec)
7、 查询没有报李平老师课的学生姓名
# 步骤
1 查出李平老师的id
select tid from teacher where tname = '李平老师';
2 连接成绩表和教师表生出虚拟表a
select * from score inner join course on score.course_id = course.cid;
3 根据指定的老师id在虚拟表a中选出所有的学生id
select * from (select * from score inner join course on score.course_id = course.cid) as a where a.teacher_id=2;
4 筛选出符合条件的学生id
select student_id from (select * from score inner join course on score.course_id = course.cid) as a where a.teacher_id=2 group by student_id;
5 运用in条件在学生列表中反向筛选出不符合条件的老师即可
select sname from student where sid not in (select student_id from (select * from score inner join course on score.course_id = course.cid) as a where a.teacher_id=2 group by student_id);
8、 查询物理课程比生物课程高的学生的学号
# 虚构出成绩列表,包含学生id、生物课程的成绩、物理课程的成绩;
1 虚构出生物成绩的学生id和num
select student_id, num from score where course_id = 1 ;
2 虚构出生物成绩的学生id和num
select student_id, num from score where course_id = 2 ;
3 连接两个表同时进行筛选
mysql> select * from (select student_id, num from score where course_id = 1) as a inner join (select student_id, num from score where course_id = 2) as b on a.student_id = b.student_id having a.num>b.num;
+------------+-----+------------+-----+
| student_id | num | student_id | num |
+------------+-----+------------+-----+
| 1 | 10 | 1 | 9 |
| 3 | 77 | 3 | 66 |
| 4 | 79 | 4 | 11 |
| 5 | 79 | 5 | 11 |
| 9 | 91 | 9 | 88 |
| 10 | 90 | 10 | 77 |
| 11 | 90 | 11 | 77 |
| 12 | 90 | 12 | 77 |
+------------+-----+------------+-----+
8 rows in set (0.00 sec)
9、 查询没有同时选修物理课程和体育课程的学生姓名
# 物理课程的学生id
select student_id from score where course_id=(select cid from course where cname='物理');
# 体育课程的学生id
select student_id from score where course_id=(select cid from course where cname='体育');
# 连接两个表
mysql> select a.student_id from (select student_id from score where course_id=(select cid from course where cname='体育')) as a inner join
(select student_id from score where course_id=(select cid from course where cname='物理')) as b on a.student_id=b.student_id;
+------------+
| student_id |
+------------+
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
| 10 |
| 11 |
| 12 |
+------------+
10 rows in set (0.00 sec)
10、查询挂科超过两门(包括两门)的学生姓名
# 步骤1:挂科超过两名的学生的id
select student_id, count(course_id) from score where num<60 group by student_id having count(course_id)>=2;
# 步骤2:连接两个表
mysql> select student.sname from (select student_id, count(course_id) from score where num<60 group by student_id having count(course_id)>=2) as a inner join student on student.sid=a.student_id;
+-------+
| sname |
+-------+
| 理解 |
+-------+
1 row in set (0.00 sec)
查询选修了所有课程的学生姓名
# 选修了四门课程的学生的id
select student_id, group_concat(course_id) from score group by student_id having count(course_id)=4;
# 连接两个表格
mysql> select student.sname as "学生姓名" from (select student_id, group_concat(course_id) from score group by student_id having count(cour
se_id)=4) as a inner join student on a.student_id=student.sid;
+----------+
| 学生姓名 |
+----------+
| 张三 |
| 张一 |
| 张二 |
| 张四 |
| 铁锤 |
| 李三 |
| 李一 |
| 李二 |
| 李四 |
| 如花 |
+----------+
10 rows in set (0.00 sec)
12、查询李平老师教的课程的所有成绩记录
# 将教师表和课程表合并后,在限定老师姓名和一一对应的关系
mysql> select * from course inner join teacher on teacher.tname='李平老师' and teacher.tid=course.teacher_id;
+-----+-------+------------+-----+----------+
| cid | cname | teacher_id | tid | tname |
+-----+-------+------------+-----+----------+
| 2 | 物理 | 2 | 2 | 李平老师 |
| 4 | 美术 | 2 | 2 | 李平老师 |
+-----+-------+------------+-----+----------+
2 rows in set (0.00 sec)
13、查询全部学生都选修了的课程号和课程名
mysql> select course_id from score group by course_id having count(student_id) = (select count(sid) from student);
Empty set (0.00 sec)
14、查询每门课程被选修的次数
mysql> select cname as '课程名称', count(student_id) as '选修人数' from score inner join course on score.course_id=course.cid group by cour
se_id;
+----------+----------+
| 课程名称 | 选修人数 |
+----------+----------+
| 生物 | 12 |
| 物理 | 11 |
| 体育 | 12 |
| 美术 | 12 |
+----------+----------+
4 rows in set (0.00 sec)
15、查询选修了一门课程的学生姓名和学号
# 以课程进行分组,运用聚合函数计算出每个课程的学习人数,根据人数条件找出对应的学生姓名
select sname from score inner join student on score.student_id = student.sid group by student_id having count(course_id)=1;
| sname |
+-------+
| 刘三 |
+-------+
1 row in set (0.00 sec)
16、查询所有学生考出的成绩并按从高到低排序(成绩去重)
mysql> select distinct num from score order by num desc;
17、查询平均成绩大于85的学生姓名和平均成绩
# 合并成绩表和学生表,根据姓名分组求出组内的平均成绩
mysql> select sname, avg(num) as average_num from score inner join student on score.student_id = student.sid group by student.sname having avg(num) > 85;
+-------+-------------+
| sname | average_num |
+-------+-------------+
| 刘三 | 87.0000 |
+-------+-------------+
1 row in set (0.00 sec)
18、查询生物成绩不及格的学生姓名和对应生物分数
mysql> select sname, num from score inner join student on score.student_id = student.sid where score.course_id = (select cid from course where cname="生物") having num < 60;
+-------+-----+
| sname | num |
+-------+-----+
| 理解 | 10 |
| 钢蛋 | 8 |
| 张四 | 9 |
| 铁锤 | 9 |
| 李三 | 9 |
+-------+-----+
5 rows in set (0.00 sec)
19、查询在所有选修了李平老师课程的学生中,这些课程(李平老师的课程,不是所有课程)平均成绩最高的学生姓名
# 先找出成绩最好学生的id,然后再在学生表中查询
mysql> select sname from student where sid = (select student_id from score inner join course on score.course_id = course.cid where teacher_id = (select tid from teacher where tname = '李平老师') group by student_id order by avg(num) desc limit 1);
+-------+
| sname |
+-------+
| 张四 |
+-------+
1 row in set (0.00 sec)
20、查询每门课程成绩最好的前两名学生的姓名
#有点复杂!
21、查询不同课程但成绩相同的学号,课程号,成绩
22、查询没学过“叶平”老师课程的学生姓名以及选修的课程名称;
23、查询所有选修了学号为1的同学选修过的一门或者多门课程的同学学号和姓名;
24、任课最多的老师中学生单科成绩最高的学生姓名
以上是关于数据库04: 多表查询的主要内容,如果未能解决你的问题,请参考以下文章