一. 概述
简单理解就是从多张表中查询数据 (select 字段列表 from 表名1,表名2...;)
但是这样写会出现笛卡尔积(指在数学中,两个集合之间的所有组合情况),因此多表查询时,需要使用某些条件消除无效的笛卡尔积
例如:select * from 表名1,表名2... where [条件]; #隐式内连接的方式
二. 分类:连接查询、子查询
先给出表格结构:
完整数据表:
1. 隐式内连接、显式内连接:两个表的交集部分
- 隐式内连接:select 字段列表 from 表名1,表名2 where 条件...;
- 显式内连接:select 字段列表 from 表名1 [inner] join 表2 on 连接条件..; -- inner可以不加
eg:查询每一个员工的姓名及关联的部门的名称(需要查询两张表)
隐式:select emp.name,dept.name from emp,dept where emp.dept_id=dept.id; #使用 emp.dept_id=dept.id 消除笛卡尔积
显式:select emp.name,dept.name from emp join dept on emp.dept_id=dept.id; #inner可以不加
通常给表名起别名:select e.name,d.name from emp [as] e inner join dept [as] d on e.dept_id=d.id; # as可以不加
2. 左外连接:左表的所有数据 和 两个表格的交集部分
select 字段列表 from 表名1 left [outer] inner join 表名2 on 条件...; -- outer可以不加
eg:查询emp的所有数据及其对应的部门信息
select e.*,d.name from emp e left join dept d on e.dept_id=d.id;
3. 右外连接:右表的所有数据 和 两个表格的交集部分(通常使用左外连接代替)
select 字段列表 from 表名1 right [outer] join 表名2 on 条件...; -- outer可以不加
eg:查询dept表的所有数据和对应的员工信息
select d.*,e.* from emp e right join dept d on e.dept_id=d.id; -- 注:右外连接右边表为dept
通常使用左外连接(代替右外连接):select d.*,e.* from dept d left join emp e on e.dept_id=d.id;
4. 自连接:可以是内连接查询也可以是外连接查询
select 字段列表 from 表名1 别名1 join 表名1 别名2 on 条件...; -- 需要给表格起别名才能分辨为两张相同表
eg:
1. 查询员工(name)及其领导(managerid)的名字; #内连接查询,其实就是看成两张相同的表进行内连接查询,取交集部分
select a.name,b.name from emp a join emp b on a.managerid=b.id; #其实就是看成两张相同的表格
2. 查询所有员工及其领导的名字。如果员工没有领导也要查询出来 #左外连接,包含左边表的全部信息和交集部分
select a.name '员工',b.name '领导' from emp a left join emp b on a.managerid=b.id;
5. 联合查询:其实就是简单将多次查询的结果合并起来形成新的查询结果
select 字段列表 from 表名1 ... union [all] select 字段列表 from 表名2 ...;
对于联合查询,有两种实现方式,union 和 union all
- union all:将两次单表查询的结果进行合并
- union : 将两次单表查询的结果进行合并,且去除重复元素
!!!注:联合查询时,多张表的列数必须保持一致,字段类型也需要保持一致。
eg:将薪资低于5000,年龄大于50的员工全部查出
select * from emp where salary<5000 union [all] select * from emo where age>50; -- 加上all之后重复元素将被去除
-- 比如存在薪资低于5000且年龄大于50的员工,加上all之后只会查出一条数据。不加上all的话可能会出现多条重复
6. 子查询:SQL语句中嵌套SELECT语句,又称为嵌套查询
还是原来的数据表,放这里容易查看:
标量子查询:子查询的结果是单个值
eg:查询销售部的所有员工信息
需求分析拆解:先去dept表查询销售部id,然后根据id去emp表查询员工信息
1.查询销售部的员工id
select id from dept where name='销售部'; -- 4(子查询的结果为单个值)
2.根据员工id查询所有员工信息
select * from emp where dept_id='4';
3.合并需求
select * from emp where dept_id = (select id from dept where name='销售部');
列子查询:子查询的结果为一列(可以是多行)
常见操作符:
- in:在指定的集合范围中,多选一
- not in:不在指定的集合范围中
- any、some:子查询返回列表中,有任意一个满足即可
- all:子查询返回列表的所有值都必须满足
以下第二步返回结果(单列多行)
eg:查询比财务部所有人工资都高的员工信息
需求分析拆解:先在dept表中查询财务部部门id,然后根据部门id去emp表中查询所属员工薪水,再拿该薪水去跟emp所有员工比较
1.查询财务部部门id
select id from dept where name='财务部'; -- 3
2.根据财务部部门id查询所有财务部员工工资
select salary from emp where id = 3;
合并为:select salary from emp where id = (select id from dept where name='财务部'); -- 标量子查询
3.查询比财务部员工工资高的员工信息
select * from emp where salary > all(select * from emp where id=(select id from dept where name='财务部'))
行子查询:返回结果是一行(可以是多列)
以下第一步返回结果(单行多列)
eg:查询与‘张无忌’及其managerid相同的员工信息
需求分析拆解:先查询‘张无忌’及其managerid,拿着这些信息去emp表中查询跟其一样的员工信息。返回结果单行多列所以叫行子查询
1.查询‘张无忌’及managerid的信息
select salary,managerid from emp where name='张无忌';
2.查询与‘张无忌’及其managerid相同的员工信息
select * from emp where salary=12500 and managerid=1;
这里需要将行子查询的结果赋值给salary和managerid,改变下sql写法:
select * from emp where (salary,managerid)=(12500,1);
即:select * from emp where (salary,managerid)=(select salary,managerid from emp where name='张无忌')
如果这里查询的结果是两行两列(多行多列为表子查询),则这里将=改成in即可,相信不用解释趴~
表子查询:返回结果是多行多列
eg:查询入职日期在‘2006-01-01’之后的员工信息及其部门信息
需求分析拆解:从emp表查询入职日期在‘2006-01-01’之后的员工信息,查询出来的数据集作为下次查询的原数据。
注:这里有的员工部门信息为null,也需要查询出来。因此需要用到左外连接
1.查询入职日期在‘2006-01-01’之后的员工信息
select * from emp where entrydate>'2006-01-01';
2.根据查询结果的managerid从dept表中查询对应员工部门
select e.*,d.* from (select * from emp where entrydate>'2006-01-01') e left join dept d where e.dept_id=d.id;