【MySQL必知必会】:联结表

451 阅读5分钟

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

联结

表的联结是 SQL 的强大功能之一,我们可以在数据检索查询的执行中联结(join)表。在学习联结的知识点之前,我们先来了解一下关系表以及关系数据库设计。

关系表

假设我们现在有两张表:

  • 供应商表:供应商的名字、地址、联系方式等

  • 产品表:包含了产品类别、产品描述、产品价格、生产该产品的供应商等

也就是说,我们将供应商的信息与产品信息分开存储。

这样做的好处在于:

  • 避免重复:供应商的信息不重复,则不会浪费时间和空间
  • 更改方便:如果供应商的信息需要更新,则只需要改动一次即可
  • 数据一致:数据没有重复,显然数据是一致的,这也便于处理数据

为了避免相同数据出现多次,我们就需要将信息拆分为多张表,一类数据划分为一张表。这就是关系表设计的基础。

在关系表的设计中,各个表之间通过某些值(即关系设计中的关系)进行互相关联。

在前面的例子中:

  • 供应商表 vendors:包含所有供应商信息,并且每个供应商都具有唯一的标识,我们称之为 主键(primary key),一般是供应商ID。

  • 产品表 products:包含了所有产品信息以及供应商ID(也就是 vendors 表中的主键)。需要注意, vendors 表中的主键又称为 products 表的 外键。这个外键的作用就是将 vendors表和 products 表关联起来。通过供应商ID能从 vendors 表中找到相应的供应商信息。

备注:

  • 主键:能够唯一区分表中每个行的值。
  • 外键:包含另一张表的主键值,将两张表联系起来

为什么要使用联结?

为什么要使用联结?因为我们想要用一条 select 语句检索出存储在多个表的数据。

前面讲过,将需要存储的数据分解为多张表的好处有很多,比如存储更加高效、处理方便 和 具有良好的可伸缩性等。

在关系型数据库中,关系表是由数据行构成的集合,我们更倾向于将数据分解存储。不仅实体对象存储在关系表中,对象之间的联系也存储在关系表中。因此,如果我们想得到某些相关联的数据,就必须使用到 联结

简单来说:

  • 联结是一种机制,用来在一条 SELECT 语句中关联表,因此称为联结。
  • 使用指定的语法,就可以联结多张表并返回一组输出。
  • 表之间的关系是在运行时构造的,联结在运行时关联表中正确的行。

创建联结

创建联结的要求有两个:

  • 指明 要联结的所有表
  • 指明 联结的方式

等值联结

等值联结:基于两个表之间的相等测试进行的联结称为等值联结。

下面的例子使用了 where 子句来建立联结关系。

SELECT
	vend_name, prod_name, prod_price
FROM
	vendors, products
WHERE
	vendors.vend_id = products.vend_id;

记录:

  • FROM 子句列出了两个表vendorsproducts,指明了 要联结的表
  • WHERE 子句指示 MySQL 匹配 vendors 表中的字段 vend_idproducts 表中的字段 vend_id,指明了 联结的方式

注意:

  • 完全限定列名:用一个点分隔的表名和列名
  • 使用时机:引用的列可能出现二义性时

为什么使用 WHERE 子句可以建立联结关系?

这是因为在MySQL 数据库表的定义中不存在指示 MySQL 如何对表进行联结的东西,我们必须手动匹配,将相应的关系在运行中进行构造。因此,使用 WHERE 子句作为过滤条件,可以轻松匹配给定的联结条件的行。

笛卡尔积

  • 如果在查询多张表的时候不使用 WHERE 子句进行联结过滤,那么返回的结果将是另一个模样,我们将其称之为笛卡尔积。
  • 所谓笛卡尔积,就上面这个例子而言,返回的数据会用每个供应商匹配了每个产品,一个产品将所有供应商都对应一遍,这是不实际的。
  • 因此在笛卡尔积中,检索出的行的数目将是第一个表中的行数乘以第二个表中的行数。这并不是我们想要的结果。
  • 为了避免发生这种情况,我们需要保证所有的联结都有 where 子句。

内部联结

前面记录了等值联结的使用。事实上,等值联结也称为内部联结。我们可以使用特定的语法来指定联结的类型。

来看这个例子:

SELECT
	vend_name, prod_name, prod_price
FROM
	vendors inner join products
on
	vendors.vend_id = products.vend_id;

记录:

  • 上述例子的返回结果与前面的例子相同。
  • 我们可以观察到,在 FROM 子句中,我们使用 inner join 来指定两个表之间的联结关系。
  • 注意,在这种情况下的过滤条件不是由 where 子句给出,而是使用 on 子句。

联结多个表

SOL 对一条 SELECT 语句中可以联结的表的数目没有限制。

创建联结的基本规则:

  • 列出所有表
  • 定义表之间的关系

下面举一个例子,返回编号为 1001 的订单的物品:

SELECT
	prod_name, vend_name, prod_price, quantity
FROM
	orderitems, products, vendors
WHERE
	products.vend_id = vendors.vend_id
	AND orderitems.prod_id = products.prod_id
	AND order_num = 1001;

记录:

  • products.vend_id = vendors.vend_id:产品表 和 供应商表 通过 vend_id 联结
  • orderitems.prod_id = products.prod_id:订单表 和 产品表 通过 prod_id 联结
  • order_num = 1001 :过滤出订单编号为 1001 的产品。

避免联结不必要的表

  • MySQL在运行时关联指定的每个表以处理联结。

  • 联结的表越多,性能下降越厉害。