MySQL中的多表查询①

举报
十八岁讨厌编程 发表于 2022/08/06 01:09:42 2022/08/06
【摘要】 目录 为什么使用多表查询使用多表查询的前提 笛卡尔积的错误多表查询的分类等值连接 vs 非等值连接自连接 vs 非自连接内连接 vs 外连接 为什么使用多表查询 使用多表查询的目的...

为什么使用多表查询

使用多表查询的目的肯定是因为你要的数据在多张表里面。有人可能会单独去查询每张表,很显然那样效率是很低的。还有人会说为什么要把数据放在多张表里面呢,放在一张里面不行吗?可以,但是会有缺点:

  • 会出现很多冗余的数据
  • 冗余的数据会造成内存的过度消耗
  • 冗余的数据会造成IO的次数变多,从而减少了效率
  • 不方便维护

使用多表查询的前提

这些一起查询的表之间是有关系的(一对一、一对多),它们之间一定是有关联字段,这个关联字段可能建立了外键,也可能没有建立外键。比如:员工表和部门表,这两个表依靠“部门编号”进行关联。

笛卡尔积的错误

想要理解笛卡尔积的错误,那么首先我们就要知道什么是笛卡尔积
笛卡尔乘积 是一个数学运算。假设我有两个集合 X 和 Y,那么 X 和 Y 的笛卡尔积就是 X 和 Y 的所有可能组合,也就是第一个对象来自于 X,第二个对象来自于 Y 的所有可能。组合的个数即为两个集合中元素个数的乘积数。

SQL92中,笛卡尔积也称为 交叉连接 ,英文是 CROSS JOIN 。在 SQL99 中也是使用 CROSS JOIN表示交叉连接。它的作用就是可以把任意表进行连接,即使这两张表不相关。

例如:
已知我们有107员工,27个部门

多表的相关数据:
多表的相关数据

出现笛卡尔积的错误

#错误的实现方式1:每个员工都与每个部门匹配了一遍。
SELECT employee_id,department_name
FROM employees,departments;  #查询出2889条记录

#错误的方式2
SELECT employee_id,department_name
FROM employees CROSS JOIN departments;#查询出2889条记录

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

很明显这是一个笛卡尔积的错误:107*27 = 2889.

笛卡尔积的错误发生条件:

  • 省略多个表的连接条件(或关联条件)
  • 连接条件(或关联条件)无效
  • 所有表中的所有行互相连接

为了避免笛卡尔积, 可以在 WHERE 加入有效的连接条件。

标准的代码实现:

SELECT emp.employee_id,dept.department_name,emp.department_id
FROM employees emp,departments dept
WHERE emp.`department_id` = dept.department_id;

  
 
  • 1
  • 2
  • 3

注意点
①如果查询语句中出现了多个表中都存在的字段,则必须指明此字段所在的表
②从sql优化的角度,建议多表查询时,每个字段前都指明其所在的表。
③可以给表起别名,在SELECT和WHERE中使用表的别名。在FROM中命令别名(易知FROM语句是最先执行的)
④如果给表起了别名,一旦在SELECT或WHERE中使用表名的话,则必须使用表的别名,而不能再使用表的原名。
如果有n个表实现多表的查询,则需要至少n-1个连接条件

多表查询的分类

角度1:等值连接 vs 非等值连接

角度2:自连接 vs 非自连接

角度3:内连接 vs 外连接

等值连接 vs 非等值连接

非等值连接就是不使用等号去连接
例如:
现有两个表employees,job_grades。前一张表记载了每一位员工的工资,后一张表记载了相应工资区间对应的工资等级。
工资等级
现在的需求是得到每一位员工的工资等级
代码实现

SELECT e.last_name,e.salary,j.grade_level
FROM employees e,job_grades j
#where e.`salary` between j.`lowest_sal` and j.`highest_sal`;
WHERE e.`salary` >= j.`lowest_sal` AND e.`salary` <= j.`highest_sal`;

  
 
  • 1
  • 2
  • 3
  • 4

自连接 vs 非自连接

自连接:很好理解就是自己与自己链接
例子:
在员工表employees中,有如下属性:
在这里插入图片描述
我们现在的需求是找出每一位员工对应的主管的id(也就是图中的manager_id),我们可以知道不论是员工还是他的主管他们肯定是在员工表之内的,从而我们很容易想到使用自连接
代码实现:

SELECT emp.employee_id,emp.last_name,mgr.employee_id `manager_id`,mgr.last_name `last_name` 
FROM employees emp ,employees mgr
WHERE emp.`manager_id` = mgr.`employee_id`;

  
 
  • 1
  • 2
  • 3

结果:(部分)
在这里插入图片描述

内连接 vs 外连接

除了查询满足条件的记录以外,外连接还可以查询某一方不满足条件的记录。
内连接: 合并具有同一列的两个以上的表的行, 结果集中不包含一个表与另一个表不匹配的行
外连接: 两个表在连接过程中除了返回满足连接条件的行以外还返回左(或右)表中不满足条件的行 ,这种连接称为左(或右) 外连接。没有匹配的行时, 结果表中相应的列为空(NULL)。

外连接的分类:左外连接、右外连接、满外连接
如果是左外连接,则连接条件中左边的表也称为 主表 ,右边的表称为 从表 。
如果是右外连接,则连接条件中右边的表也称为 主表 ,左边的表称为 从表 。

我们可以用两个集合来形象的理解这些概念:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
那么我们怎么实现外连接呢?
在SQL92语法中我们可以直接使用"+",完成外连接。
右外连接 在左边补加号
左外连接 在右边补加号
也就是说哪边是从表哪边补一个加号

注意

  • Oracle 对 SQL92 支持较好,而 MySQL 则不支持 SQL92 的外连接
  • 而且在 SQL92 中,只有左外连接和右外连接,没有满(或全)外连接。

例如:我们现在有一个需求查询所有的员工的last_name,department_name信息 (已知有的员工没有部门,有的部门没有员工)

很明显这个地方要使用左外连接,因为他要求的是所有的员工
代码实现:

#MySQL不支持:
SELECT employee_id,department_name
FROM employees e,departments d
WHERE e.`department_id` = d.department_id(+);

  
 
  • 1
  • 2
  • 3
  • 4

文章来源: blog.csdn.net,作者:十八岁讨厌编程,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/zyb18507175502/article/details/122649892

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。