联结

  • SQL最强大的功能之一就是能在数据检索查询的执行中联结表。

关系表

  • 关系表的设计就是要保证把信息分解成多个表,一类数据一个表。各表通过某些常用的值(即关系设计中的关系)互相关联。

  • 外键:外键为某个表中的一列,它包含另一个表的主键值,定义了两表之间的关系。

    这样做的好处:

    1. 供应商信息不重复,从而不浪费时间和空间;
    2. 如果供应商信息变动,可以只更新vendors表中的单个记录,相关表中的数据不用改动;
    3. 由于数据无重复,显然数据是一致的,这使得处理数据更简单。
  • 可伸缩性:能够适应不断增加的工作量而不失败。设计良好的数据库或应用程序称之为可伸缩性好。

  • 关系数据可以有效的存储和方便的处理。因此关系型数据库的可伸缩性远比非关系数据库要好。

为什么要使用联结

  • 联结是一种机制,用来在一条SELECT语句中关联表,可以联结多个表返回一组输出。

  • 维护引用完整性:在使用关系表时,仅在关系列中插入合法的数据非常重要。

    如果在products表中插入拥有非法供应商ID(即没有在vendors表中出现)的供应商生产的产品,则这些产品是不可访问的,因为他们没有关联到某个供应商。

    为防止这种情况发生,可指示MySQL只允许在products表的供应商ID列中出现合法值(即出现在vendors表中的供应商),这就是维护引用完整性,他是通过在表的定义中指定主键和外键来实现的。

创建联结

1
2
3
4
5
6
7
SELECT vend_name, prod_name, prod_price
FROM vendors, products
WHERE vendors.vend_id = products.vend_id
ORDER BY vend_name, prod_name;

-- 这两个表用WHERE子句正确联结
-- WHERE子句指示MySQL匹配vendors表中的vend_id和products表中的vend_id
  • 完全限定列名:在引用的列可能出现二义性时,必须使用完全限定列名(用一个点分隔的表名和列名)。

WHERE子句的重要性

  • 在联结两个表时,实际上做的是将第一个表中的每一行与第二个表中的每一行配对。

    WHERE子句作为过滤条件,它只包含那些匹配给定条件(这里是联结条件)的行。

    没有WHERE子句,第一个表中的每个行将与第二个表中的每个行配对,而不管他们逻辑上是否可以配在一起。

  • 笛卡尔积:由没有联结条件的表关系返回的结果为笛卡尔积。检索出的行的数目将是第一个表中的行数乘以第二个表中的行数。

1
2
3
4
-- 笛卡尔积示例
SELECT vend_name, prod_name, prod_price
FROM vendors, products
ORDER BY vend_name, prod_name;
  • 不要忘了WHERE子句:应该保证所有联结都有WHERE子句,否则MySQL将返回比想要的数据多得多的数据。同理,应该保证WHERE子句的正确性。
  • 叉联结:有时我们会听到返回称为叉联结的笛卡尔积的联结类型。

内部联结

  • 目前为止所用的联结称为等值联结,它基于两个表之间的相等测试。这种联结也称为内部联结

    对于这种联结可以使用稍微不同的语法来明确指定联结的类型。

1
2
3
SELECT vend_name, prod_name, prod_price
FROM vendors INNER JOIN products
ON vendors.vend_id = products.vend_id;
  • 使用哪种语法:ANSI SQL规范首选INNER JOIN语法。

    使用明确的联结语法能够确保不会忘记联结条件,有时候这样做也会影响性能。

联结多个表

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

  • 性能考虑:MySQL在运行时关联指定的每个表以处理联结。

    这种处理可能是非常耗费资源的,不要联结不必要的表;联结的表越多,性能下降越厉害。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
-- 返回订购产品TNT2的客户列表
SELECT cust_name, cust_contact
FROM customers
WHERE cust_id IN (SELECT cust_id
FROM orders
WHERE order_num IN (SELECT order_num
FROM orderitems
WHERE prod_id = 'TNT2'));
-- 等同于以下
SELECT cust_name, cust_contact
FROM customers, orders, orderitems
WHERE customers.cust_id = orders.cust_id
AND orderitems.order_num = orders.order_num
AND prod_id = 'TNT2';
  • 多做实验:性能可能会受操作类型、表中数据量、是否存在索引或键以及一些其他条件的影响;

    因此,有必要对不同的选择机制进行实验,以找出最适合具体情况的方法。