MySQL:关联查询

188 阅读6分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 6 天,点击查看活动详情


关联查询:两个或更多个表一起查询。

关联查询结果的7种情况

image-20211201000449563.png

两个表一起查询的前提条件:两表之间必须有关联。即要有相同逻辑意义和数据类型的字段

情况一:A∩B image.png

我们发现,AB两表里都存在部门编号,这就是他们的关联,逻辑意义相同,数据类型也相同

现在要找 A∩B的情况,那就从关联里找相同的,比如说A表中D1001可以对应B表的D1001,那么把AB表的这一行组合在一起就行。最后有个NULL值在B表中无对应,则舍弃。

另外,B表中D1004在A表无对应数据行,直接剔除

情况二:A

image.png

这种情况就是A的数据要全保留,仔细看图应该不难发现A∩B组合之后,还剩一个王五那一行在B表中没有对应的关联数据,那就直接写NULL。

情况三:A-A∩B

image.png

就是把AB有关联的全剔除,只留下A表中在B表无关联的数据

情况四:B

image.png

和情况二是反过来的,仔细看一下情况二,是保留A∩B和A中所有数据,所以B表中无效数据D1004那一行被踢掉。

但这里是保留A∩B和B中所有数据,所以A表中无效数据S1005王五,那一行被踢掉。

情况五:B-A∩B

image.png

就是把AB有关联的全剔除,只留下B表中在A表无关联的数据,和情况三相反。

情况六:A∪B

image.png

AB的数据全都要

情况七:A∪B-A∩B

image.png

取A表没交集的和B表没交集的


两个表的记录分为四种:

①A表中能在B表中找到对应的记录的记录

②A表中在B表中找不到对应的记录的记录

③B表中可以在A表找到对应的记录的记录

④B表中在A表中找不到对应的记录的记录

  1. A∩B ①③
  2. A ①②
  3. A-A∩B ②
  4. B ③④
  5. B-A∩B ④
  6. A∪B ①②③④
  7. A∪B-A∩B ②④

如何实现7种查询结果

  1. 内连接 inner join
  2. 外连接 outer join
  • 左外连接 left outer join 或 left join
  • 右外连接 right outer join 或 right join
  • 全外连接 full outer join 或 full join

注意:MySQL不支持全外连接,它是通过union关键字合并其他的查询结果实现全外连接

下面是几种连接和查询结果的对应关系:

  • 内连接 ==> A∩B
  • 左连接 ==> A 或 A-A∩B
  • 右连接 ==> B 或 B-A∩B
  • 全外连接 ==> A∪B 或 A∪B-A∩B

既然MySQL不支持全外连接,其中A∪B通过左连接的A union 右连接的B实现

A∪B-A∩B通过左连接的A-A∩B union 右连接的B-A∩B实现


内连接

#查询员工表的员工姓名,和部门编号,部门表的部门名称
#不显示那些 没有分配部门的员工,也不包括那么没有员工的部门
select ename,t_employee.did,dname -- 两个表中都有did,要指明那个表的did
from t_employee inner join t_department
on t_employee.did = t_department.did -- 要指明按照部门编号进行关联

左连接

语法:

  1. A表 left join B表 on A表.关联字段 = B表.关联字段(对应A查询结果)
  2. A表 left join B表 on A表.关联字段 = B表.关联字段 where A表和B表中是从表.关联字段 is null(对应A-A∩B查询结果)
#查询所有的员工姓名和部门编号,部门名称,包括那些没有分配部门的员工
#但不包括没有员工的部门
select ename,t_employee.did,dname
from t_employee left join t_department
    on t_employee.did = t_department.did;

#查询所有员工的姓名和部门编号,部门名称,只显示那些没有分配部门的员工
#但不包括没有员工的部门
select ename,t_employee.did,dname
from t_employee left join t_department
on t_employee.did = t_department.did
where t_employee.did is null ;

右连接

语法:

  1. A表 right join B表 on A表.关联字段 = B表.关联字段(对应B查询结果)
  2. A表 right join B表 on A表.关联字段 = B表.关联字段 where 从表.关联字段 is null(对应B-A∩B查询结果)
#查询所有部门的编号,部门的名称,以及该部门下所有的员工信息
#包括那些没有员工的部门,不包括没有分配部门的员工
select t_department.did,dname,t_employee.*
from t_employee right join t_department
    on t_employee.did = t_department.did;
    
#查询所有部门的编号,部门的名称,以及该部门下所有的员工信息
#只显示那些没有员工的部门,不包括没有分配部门的员工
select t_department.did,dname,t_employee.*
from t_employee right join t_department
    on t_employee.did = t_department.did
where t_employee.did is null ;
/*
 部门表是主表,员工表示从表
 两个表的关联字段是did(部门编号)
 部门表中是所有部门的信息,是完整的部门信息
 员工表选择所属部门时,必须参考部门表,选择的部门编号必须在部门表中找得到。
 */

union合并查询结果

语法:

  1. A∪B:左连接的A union 右连接的B
  2. A∪B-A∩B:左连接的A-A∩B union 右连接的B-A∩B
# 查询所有员工和所有部门的信息,包括那些没有员工的部门,和没有分配部门的员工
# 也包括有员工的部门,和有部门的员工
select *
from t_employee left join t_department
    on t_employee.did = t_department.did
union
select *
from t_employee right join t_department
    on t_employee.did = t_department.did;

#查询所有员工和所有部门的信息
#只显示那些没有部门的员工,没有员工的部门
select *
from t_employee left join t_department
on t_employee.did = t_department.did
where t_employee.did is null
union
select *
from t_employee right join t_department
on t_employee.did = t_department.did
where t_employee.did is null ;

特殊的内连接

之前的内连接,我们使用的是A表 inner join B表 on 条件 现在我可以改成不用inner join ,写成A表 , B表 where 条件

#查询员工和部门的信息,只显示有部门的员工和有员工的部门
select *
from t_employee , t_department
where t_employee.did = t_department.did;

更多表关联

职位表和员工表的job_id关联,部门表和员工表的did关联。

需要注意的是:n张表关联,关联条件要编写n-1个

这里的关联条件有:

  • t_employee.did = t_department.did
  • t_employee.job_id = t_job.jid

基本语法:A表 inner|left|right join B表 on 关联条件1 inner|left|right join C表 on 关联条件2

#查询每一个员工的姓名,职位名称,部门名称
# 姓名在t_employee,职位在t_job,部门在t_department表中
select ename,jname,dname
from t_employee left join t_department  on t_department.did = t_employee.did
left join t_job  on t_employee.job_id = t_job.jid;