MySQL学习·第四站~
本文已收录至专栏:MySQL通关路
❤️文末附全文思维导图,感谢各位点赞收藏支持~
之前我们介绍DQL语句,也就是数据查询语句的时候,介绍的查询操作都是单表查询,他的功能当然不仅局限于此,我们还可以一次性对多个表的数据进行查询操作,也就是接下来要介绍的多表查询。
在我们的项目开发中,在进行数据库表结构设计时,会根据业务需求及业务模块之间的关系,分析并设计表结构,由于业务之间经常会存在相互关联关系,所以由此设计出的各个表结构之间也存在着各种联系,基本上分为三种:
多表查询就是指一次性从多张表中查询数据。
原来我们查询单表数据,执行的SQL形式为:select 字段列表 from 表名;
现在我们想要执行多表查询,就只需要使用逗号分隔多张表即可,如: select 字段列表 from 表名1, 表名2;
但是我们这样使用却发现存在问题:的确同时查到了多张表的数据,但是数据形式和我们想要的并不一样,它排列组合了两张表中的所有数据项!
例如我们查询员工、部门表,本来我们预期是每个员工对应其所在的部门,但事实确实,每个员工都对应了所有部门。这种现象也称之为 笛卡尔积 。
因此,在多表查询中,我们需要根据业务情况进行连接查询,消除无效的笛卡尔积,只保留两张表关联部分的有效数据。
例如在上述示例,我们通过表名.字段名
指定员工表的外键等于部门表的主键即可获得预期数据~
特别说明:
table as 别名或table 别名
表名.字段名
来进行指定。内连接查询的是两张表交集部分的数据(也就是绿色部分的数据)。语法分为两种: 隐式内连接、显式内连接。
SELECT 字段列表 FROM 表1,表2 WHERE 限制条件;
# 查询每一个员工的姓名 , 及关联的部门的名称
select e.name,d.name from emp e,dept d where e.dept_id = d.id;
SELECT 字段列表 FROM 表1 [ INNER ] JOIN 表2 ON 连接条件 ... ;
# 查询每一个员工的姓名 , 及关联的部门的名称
select e.name, d.name from emp e inner join dept d on e.dept_id = d.id;
外连接分为:左外连接 和 右外连接。左外连接相当于查询表1(左表)的所有数据,当然也包含表1和表2交集部分的数据。右外连接相当于查询表2(右表)的所有数据,当然也包含表1和表2交集部分的数据。
SELECT 字段列表 FROM 表1 LEFT [ OUTER ] JOIN 表2 ON 条件 ... ;
# 查询emp表的所有数据, 和对应的部门信息
select e.*, d.name from emp e left outer join dept d on e.dept_id = d.id;
不仔细看会觉得和内连接没啥区别,但是仔细看会发现我们null数据也能够正常显示出来,而内连接则无法查询到null,这是因为我们外连接会获取到一张表的全部数据,而内连接只获取交集部分数据。
SELECT 字段列表 FROM 表1 RIGHT [ OUTER ] JOIN 表2 ON 条件 ... ;
# 查询emp表的所有数据, 和对应的部门信息
select e.*, d.name from emp e left outer join dept d on e.dept_id = d.id;
这么一看感觉左右外连接查询结果都差不多,确实如此,通常左外连接和右外连接是可以相互替换的,只需要调整在连接查询时SQL中,表结构的先后顺序就可以了。而我们在日常开发使用时,更偏向于左外连接。
自连接查询,顾名思义,就是自己连接自己,也就是把一张表进行连接查询多次。需要注意的是在自连接查询中,必须要为表起别名,要不然我们不清楚所指定的条件、返回的字段,到底是哪一张表的字段。
SELECT 字段列表 FROM 表A 别名A JOIN 表A 别名B ON 条件 ... ;
# 查询员工 及其 所属领导的名字,如果员工没有领导, 也需要查询出来
select a.name '员工', b.name '领导' from emp a left join emp b on a.managerid =
b.id;
对于联合查询,就是把多次查询的结果合并起来,形成一个新的查询结果集。
SELECT 字段列表 FROM 表A ... # 查询结果集1
UNION [ ALL ]
SELECT 字段列表 FROM 表B ....; # 查询结果集2
注意事项
对于联合查询的多张表的字段列表必须保持一致,字段类型也需要保持一致,如果不一致将会报错。
union all
会将全部的数据直接合并在一起,union
会对合并之后的数据去重。
示例代码
select * from emp where salary < 5000
union all
select * from emp where age > 50;
union all
查询出来的结果,仅仅只对数据集进行简单的合并,查询结果中可能会存在重复数据项,使用union
即可去除重复数据项。
SQL语句中嵌套SELECT语句,称为嵌套查询,又称子查询。
# 示例语法
SELECT * FROM t1 WHERE column1 = (SELECT column1 FROM t2);
子查询外部的语句可以是INSERT / UPDATE / DELETE / SELECT
的任何一个。嵌套SELECT语句
可以位于SELECT之后
、FROM之后
、WHERE之后
。
子查询返回的结果是单个值(例如数字、字符串、日期等)。 常用的操作符有:= <> > >= < <=
# 拆分1: 查询 "销售部" 部门ID,返回单个id值
select id from dept where name = '销售部';
# 拆分2:根据部门ID, 查询员工信息
select id from dept where name = xxx;
# 完整版
select * from emp where dept_id = (select id from dept where name = '销售部');
子查询返回的结果是一列(可以是多行)。常用的操作符:IN 、NOT IN 、 ANY 、SOME 、 ALL
# 拆分1: 查询财务部id
select id from dept where name = '财务部';
# 拆分2: 查询财务部员工工资
select salary from emp where dept_id = 拆分1;
select salary from emp where dept_id = (select id from dept where name = '财务部');
# 拆分3 : 比 财务部 所有人工资都高的员工信息
select * from emp where salary > all (拆分2);
# 合并
select * from emp where salary > all ( select salary from emp where dept_id =
(select id from dept where name = '财务部') );
子查询返回的结果是一行(可以是多列)。常用的操作符:= 、<> 、IN 、NOT IN
# 拆分1:查询 "张无忌" 的薪资及直属领导
select salary, managerid from emp where name = '张无忌';
# 拆分2:查询与 "张无忌" 的薪资及直属领导相同的员工信息
select * from emp where (salary,managerid) = (xx,xx);
# 合并
select * from emp where (salary,managerid) = (select salary, managerid from emp
where name = '张无忌');
子查询返回的结果是多行多列。常用的操作符:IN
# 拆分1:查询 "鹿杖客" , "宋远桥" 的职位和薪资
select job, salary from emp where name = '鹿杖客' or name = '宋远桥';
# 拆分2:查询与 "鹿杖客" , "宋远桥" 的职位和薪资相同的员工信息
select * from emp where (job,salary) in ( xxx );
# 合并
select * from emp where (job,salary) in (select job, salary from emp where name = '鹿杖客' or name = '宋远桥');
最后值得一提是:多表查询业务能实现相关需求的SQL往往会很多, 写法也多种多样,总之,能满足我们的需求,查询出符合条件的记录即可~