开启掘金成长之旅!这是我参与「掘金日新计划 · 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
子句列出了两个表vendors
和products
,指明了 要联结的表WHERE
子句指示 MySQL 匹配vendors
表中的字段vend_id
和products
表中的字段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在运行时关联指定的每个表以处理联结。
联结的表越多,性能下降越厉害。