1.目录
联结,大致上类似于指针,就是将数据用地址的方式【压缩】起来,减少数据的冗余,提高可扩展性。联结我觉得就类似指针的解引用,将表中【压缩】的信息展开回原本的形态。
2.联结概念
冗余数据的弊端
- 浪费存储空间。 比如同一供应商的每个产品的供应商信息都是相同的,每个产品中都重复存储一遍相关信息便造成了空间的浪费;
- 难以改动。 如果供应商信息分布在每个产品中,并且被多次重复,可以想象,改动起来是相当困难的;
- 重复输入容易产生错误。 假设输入供应商信息时需要重复多次输入相同信息,可以想象,将很容易产生错误,从而导致数据的不一致;
为什么需要联结
可以类比到指针,为什么需要解引用?指针是对数据进行了【压缩】的,这样在用不到的时候就可以减少存储空间,如果要进行传输的话也能少传输很多东西,但是总有需要用到详细信息的时候,这时候肯定就需要【解压缩】了。在指针中这是解引用,在这里便是联结。
主键、外键、可伸缩性、维护应用完整性
- 主键:一张表中每行数据的标识属性,最典型的就是ID,每行中的主键必须互不相等。当然也可以用多行一同作为主键;
- 外键:A表用于关联到B表的属性,基本A表中存储的就是B表的主键,大致上就类似B的指针;
- 可伸缩性:粗略理解就是,外键、主键关联起来的这种形式,在进行信息修改时,例如修改供应商的信息,在独立的供应商表上修改就可以了;
- 维护应用的完整性,主要是讨论应用合法性的,就是例如供应商外键的值在供应商表中到底存在不存在这类,这章并没有作详细讨论;
3.联结创建
WHERE方法
就我所理解,标准联结(内/外)、自然联结(内/外)都可以用WHERE来进行实现,但是有些联结是比较难用WHERE来做的,用WHERE来实现最典型的内联结:
SELECT vend_name, prod_name, prod_price
FROM vendors, products
WHERE vendors.vend_id = products.vend_id;
JOIN方法
专门用于联结的关键字,是标准中推荐使用的,而且如果使用NATURAL JOIN的话,写起来相当方便。用JOIN实现WHERE中的例子:
SELECT vend_name, prod_name, prod_price
FROM vendors INNER JOIN products
ON vendors.vend_id = products.vend_id;
4.联结类型
具有非常多不同的联结分式,大致上,按照是否需要写联结条件和进行列去重,可分为标准联结和自然联结;按照联结方式可以分为内联结和外联结;
笛卡尔乘积联结
当使用标准内联结(INNER JOIN / JOIN)而省略联结条件的时候,得出的结果就是笛卡尔乘积联结。例如A表有6行,B表有14行,这时候就会得出84行,6*14=84。使用标准外联结(LEFT OUTER JOIN / LEFT JOIN,RIGHT同理),而不写联结条件的话会报错;
例子:
SELECT vend_name, prod_name, prod_price
FROM vendors INNER JOIN products;
标准联结、自然联结
就目前我的理解,自然联结和标准联结的主要区别就是,自然联结是一种提高效率的简化写法。自然联结会自动判断联结条件(就是外键、主键关系,如果没有的话,则进行笛卡尔乘积联结),并且会进行自动的列去重。例子如下:
- 使用标准联结
SELECT vendors.*, products.prod_id, products.prod_name,
products.prod_price, products.prod_desc
FROM vendors INNER JOIN products
ON vendors.vend_id = products.vend_id;
- 使用自然联结
SELECT *
FROM vendors NATURAL JOIN products;
不但内联结可以有自然联结实现,外联结也存在相应实现,关键字为:
NATURAL LEFT JOIN
NATURAL RIGHT JOIN
另外,在使用NATURAL RIGHT JOIN等外部联结,是用来处理这类情况的:
A.某个生产商根本没有生产过产品,但需要列出所有生厂商及产品信息,没有产品的话显示NULL;
B.某个客户根本没有下过订单,但需要列出所有客户及订单信息,没有订单的话显示NULL;
所以,会存在A表中外键为NULL,或B表中某个主键在A表没有相应的外键值的情况。
在这种情况下,自然外部联结会重新编排两个表联结后的输出顺序,例如
SELECT *
FROM products NATURAL RIGHT JOIN vendors
ORDER BY vend_id;
会先输出vendors的所有列,再在此基础上,如果有对应产品的话就联结相应的产品信息,
然而如果使用标准联结的话,属性输出顺序等是需要自行规定的。
内部联结、外部联结
这里讨论的是通过主键、外键关系联结起来的内部联结和外部联结,不过没有相应关系的话,并且不写联结条件的话,外部联结会直接报错就是了。
- 内部联结,内部联结是比较常见的联结。例子还是产品和生产商吧,如果采用内部联结的话,则会只有列出【所有生产过产品的生产商,及其生产的产品的联结信息】;
- 外部联结,外部联结也有不少的应用场景。例子同上,如果采用外部联结,以如下例子来进行说明,
会列出【被偏向的vendors表中所有的数据,如果vend_id在products有值的话,则在前者的基础上联结相关信息】,例子最终输出【生产过产品的厂商及其所有产品信息,以及没有生产过产品的厂商信息及空的产品信息】;
SELECT *
FROM products NATURAL RIGHT JOIN vendors
自联结
一种SQL技巧,例子为书中的【在products表中找出prod_id为DTNTR的行,获取其vend_id;在相同的表中,找出所有具有相同vend_id的行,输出prod_id, prod_name】。
SELECT p1.prod_id, p1.prod_name
FROM products AS p1, products AS p2
WHERE p1.vend_id = p2.vend_id AND p2.prod_id = 'DTNTR';
5.其他
别名
- 列别名,常见于使用函数后进行命名;
- 表别名,在自联结技巧中是必要的,一般情况下也可用来缩短SQL语句(能少打点字更重要);
使用带聚集函数的联结
联结可以看作一个临时表,当然也是可以使用正常表的GROUP BY、聚集函数、其他函数等的,例子为:
SELECT customers.cust_name,
customers.cust_id,
COUNT(orders.order_num) AS num_ord
FROM customers LEFT OUTER JOIN orders
ON customers.cust_id = orders.cust_id
GROUP BY customers.cust_id;
多表联结
- 虽然不知道效率如何,但是只是实现功能的话不必像书中那么麻烦,在多表联结中也可以直接使用NATURAL JOIN的,【FROM a NATURAL JOIN b NATURAL JOIN c】这样;
- 多表联结中,可以存在多种联结方式,例如【FROM a NATURAL JOIN b NATURAL LEFT JOIN c】这样;