mysql多表查询
1.多表关系
- 一对多(多对一)
- 多对多
- 一对一
2.案例
2.1一对多
案例:部门与员工
关系:一个部门对应多个员工,一个员工对应一个部门。
实现:在多的一方建立外键,只想一方的主键。
2.2多对多
案例:学生与课程
关系:一个学生可选择多门课程,一门课程可供多个学生选择。
实现:建立第三张表,中间表至少包含两个外键,分别关联两方主键。
2.3一对一
案例:用户与用户详情
关系:一对一关系,多用于单表拆分,将一张表的基础字段放在一张表中,其他详情字段放到另一张表中,以提升操作效率。
实现:在任意一方加入外键,关联另一方的主键,并设置外键为唯一的(unique)
3.准备工作
3.1部门表的创建和数据插入
# 创建部门表
create table dept(
id int auto_increment comment 'ID' primary key,
name varchar(50) unique not null comment '部门名称'
)comment '部门表';
# 插入数据
insert into dept(name) values ('研发部'),('市场部'),('财务部'),('销售部'),('总经办');
3.2 创建员工表和数据插入
# 员工表
create table emp(
id int auto_increment comment 'ID' primary key ,
`name` varchar(50) not null comment '姓名',
age int comment '年龄',
job varchar(20) comment '职位',
salary int comment '薪资',
entrydate date comment '入职时间',
managerid int comment '直属领导ID',
dept_id int comment '部门ID'
)comment '员工表';
insert into emp values
(1,'金庸',66,'总裁',20000,'2000-01-01',null,5),
(2,'张无忌',20,'项目经理',12500,'2005-12-05',1,1),
(3,'杨逍',33,'开发',8400,'2000-11-03',2,1),
(4,'韦一笑',48,'开发',11000,'2002-02-05',2,1),
(5,'常遇春',43,'开发',10500,'2004-07-09',3,1),
(6,'小昭',19,'程序员鼓励师',6600,'2004-10-12',2,1),
(7,'灭绝',60,'财务总监',8500,'2002-09-12',1,3),
(8,'周芷若',19,'会计',4800,'2006-06-02',7,3),
(9,'丁敏君',23,'出纳',5250,'2009-05-12',7,3),
(10,'赵敏',20,'市场部总监',12500,'2002-02-05',1,2),
(11,'鹿杖客',56,'职员',3750,'2006-12-05',10,2),
(12,'鹤笔翁',19,'职员',3750,'2006-05-25',10,2),
(13,'方东白',19,'职员',5500,'2002-11-05',10,2),
(14,'张三丰',88,'销售总监',14000,'2003-06-15',1,4),
(15,'俞莲舟',38,'销售',4600,'2003-07-05',14,4),
(16,'宋远桥',40,'销售',4600,'2004-09-18',14,4),
(17,'陈友谅',42,null,2000,'2010-06-16',1,null);
4.sql语句查询
4.1内连接查询
内连接查询的是两张表的交集部分。
4.1.1隐式内连接
语法 select 字段列表 from table1,table2 where 条件...;
查询员工信息及其对应部门信息。
select d.name as dname,e.name from dept d,emp e where d.id=e.dept_id;
4.1.2显示内连接
语法:select 字段列表 from table1 [inner] join table2 on 链接条件...;(中括号内字段可省略不写)。
查询员工信息及其对应部门信息。
select d.name dname,e.name from emp e inner join dept d on d.id=e.dept_id;
查询结果:
[
{
"dname": "总经办",
"name": "金庸"
},
{
"dname": "研发部",
"name": "张无忌"
},
{
"dname": "研发部",
"name": "杨逍"
},
{
"dname": "研发部",
"name": "韦一笑"
},
{
"dname": "研发部",
"name": "常遇春"
},
{
"dname": "研发部",
"name": "小昭"
},
{
"dname": "财务部",
"name": "灭绝"
},
{
"dname": "财务部",
"name": "周芷若"
},
{
"dname": "财务部",
"name": "丁敏君"
},
{
"dname": "市场部",
"name": "赵敏"
}
]
4.2外连接
4.2.1左外连接
查询左表的所有数据,以及两张表的交集部分。
语法:select 字段列表 from table1 left [outer] join table2 on 条件。
查询所有员工的信息和部门名称;
select e.*,d.name from emp e left outer join dept d on d.id=e.dept_id;
查询结果,左外连接:查询左表的所有数据,以及两张表的交集部分。所以最后一条即使没有对应的部门也会查出来。
4.2.2右外连接
查询右表的所有数据,以及两张表的交集部分。
语法:select 字段列表 from table1 right [outer] join table2 on 条件。
查询员工的信息和部门名称;
select e.*,d.name from emp e right join dept d on d.id=e.dept_id;
查询结果,右外连接查询的是dept全部信息和emp的交集,不会出现4.2.1那种查询结果。
4.2.3总结
左外连可以查到到没有dept的emp的信息,右外链可以查到没有emp的dept。
4.3自链接查询
当前表与自身的链接查询,子链接不许使用别名。
语法:select 字段列表 from table a join table b on 条件。。。;
自链接查询,也可以是内连接查询,也可以是外连接查询;
查询员工及其领导的名字(内连接)
select e.name,p.name managername from emp e inner join emp p on e.managerid=p.id;
结果,查询出emp 自身的交集
查询员工及其领导的名字(左连接)
select e.name,p.name managername from emp e left join emp p on e.managerid=p.id;
查询员工及其所属领导的名字,即使没有领导也要查出来:
4.4联合查询
把多次查询的结果合并,形成一个新的查询集。
语法
select 字段列表 from table1 ...
union [all]
select 字段列表 from table2 ...;
注意事项:
- union all 会有重复结果,union不会
- 联合查询比使用or效率高,不会是索引失效
-
联合查询的多张表的列数必须保持一直,字段类型也需要保持一致。
查询信息大于5000,年龄大于50岁。
select * from emp where salary >5000
union
select * from emp where age>50;
查询结果:
5.子查询
sql语句中嵌套select语句,称为嵌套查询,又称子查询
5.1标量子查询
子查询结果为单个值(数字,时间,字符串等)。
常用操作:<> ,>,>=,=<,=
查询销售部所有的员工
# 第一步 id=4
select dept.id from dept where name='销售部';
# 第二部,根据第一步查询的结果
select * from emp where emp.dept_id=4;
# 标量子查询(合并)
select * from emp where dept_id=(select id from dept where name='销售部');
5.2列子查询
返回的结果是一列(可以是多行)
操作符 | 描述 |
---|---|
IN | 在指定的范围合集内,多选一 |
NOT IN | 不在指定的范围合计内 |
ANY | 子查询返回的列表中,右任意一个满足即可 |
SOME | 与ANY等同 |
ALL | 子查询返回的所有值都必须满足 |
查询销售部和市场部所有员工信息
#第一步:通过dept表获取市场部和销售部id
select id from dept where name='市场部' or name='销售部';
# 第二部:通过上一步获取id,查询员工信息
select * from emp where dept_id in (2,4);
# 合并
select * from emp where dept_id in (select id from dept where name='市场部' or name='销售部');
结果
查询比财务部所有人都高的员工工资
# 第一步获取财务部id
select id from dept where name='财务部';
# 第二部获取财务部最高工资
select max(salary) from emp where dept_id='3';
#第三步获取高于财务部最高工资的员工信息
select * from emp where salary>8500;
# 合并
select * from emp where salary>all(select salary from emp where dept_id=(select id from dept where name='财务部'));
结果
#查询比财务部一些人工资高的员工。
select * from emp where salary>some(select salary from emp where dept_id=(select id from dept where name='财务部'));
select * from emp where salary>any(select salary from emp where dept_id=(select id from dept where name='财务部'));
结果
5.3行子查询
返回的子查询结果是一行(可以是多列)。
常用操作符:=,<,>,,in,not in
# 第一步获取张无忌的薪资和领导id
select salary,managerid from emp where name='张无忌';
# 第二部根据第一部信息查询员工信息
select * from emp where salary=12500 and managerid=1;
# 合并
select * from emp where (salary,managerid)=(select salary,managerid from emp where name='张无忌');
结果:
5.4表子查询
子查询结果多行多列:
常用操作符:in
查询与赵敏或周芷若相同薪资和领导的员工。
select * from emp where (salary,managerid) in (select salary,managerid from emp where name='赵敏' or name='周芷若');
结果:
6.多对多查询
准备工作
学生表
create table student(
id int auto_increment key comment '主键ID',
name varchar(10) comment '姓名',
no varchar(10) comment '学号'
)comment ' 学生表';
insert into student values (null,'黛绮丝','2000100101'),(null,'谢逊','2000100102'),(null,'殷天正','2000100103'),(null,'韦一笑','2000100104');
课程表:
create table course(
id int auto_increment key comment '主键ID',
name varchar(10) comment '课程名称'
)comment '课程表';
insert into course values (null,'Java'),(null,'PHP'),(null,'Mysql'),(null,'Hadoop')
课程学生关联表:
create table student_course(
id int auto_increment comment '主键' key,
studentid int not null comment '学生ID',
courseid int not null comment '课程ID',
constraint fk_courseid foreign key (courseid) references course(id),
constraint fk_studentid foreign key (studentid) references student(id)
)comment '学生课程中间表';
insert into student_course values (null,1,1),(null,1,2),(null,1,3),(null,2,3),(null,3,4);
查询学生选修的课程
select student.name,course.name from course,student,student_course where student.id=student_course.studentid and course.id=student_course.courseid;
结果: