关系表

设想一下,在一个产品表中,包含产品的名称,价格,描述,供应商等产品信息。但是问题是,如果多个产品都是一个供应商生产的,表中供应商字段的列信息就会重复,而且占有较多的内存空间。不仅如此,当供应商的信息发生更改时(地址或者电话、邮箱等)就会产生极大的麻烦,因此将供应商的信息独立储存在另外一个单独的表中非常有必要。这时供应商表(vendors)和产品表(products)可以用vend_id来联系起来。vend_id作为vendors表的主键和products表的外键。这样做的好处是使数据库拥有好的可伸缩性。

创建联结

联结是一种机制,可以用一条SELECT语句中关联多个表。
联结的创建只需规定联结的表以及他们是如何联结的即可。如:
SELECT vend_name,prod_name,prod_price FROM vendors,products WHERE vendors.vend_id=products.vend_id ORDER BY vend_name,prod_name;
image.png
如果没有联结条件,那查询将会返回两个表的笛卡尔积,即检索出来的行数是第一个表的行数乘以第二个表的行数,这样的数据是没有意义的,因此联结条件非常重要。

内部联结

像上面的联结其实是等值联结,也称为内部联结,它基于两个表的相等测试。其实还有一种更简洁的语法来表示这种联结,下面的语句将达到上面检索出的相同的效果:
SELECT vend_name,prod_name,prod_price FROM vendors INNER JOIN products ON vendors.vend_id=products.vend_id ORDER BY vend_name,prod_name;
image.png

注意:ANSI SQL规范首选INNER JOIN语法,以便记得添加联结条件。 尽量不要联结不必要的表,联结的表越多,性能下降地越快。

自联结

现在假设你发现产品DTNTR存在质量问题,你想查询该产品供应商所生产的其他产品是否也存在类似问题,第一步需要找到产品DTNTR的供应商id,第二步根据这个id查找它生产的其他产品。
第一种解决方法是通过子查询:
SELECT prod_id,prod_name FROM products WHERE vend_id=(SELECT vend_id FROM products WHERE prod_id=’DTNTR’);
image.png
第二种解决方法就是通过自联结:
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’;
image.png
其实就是查询了两种相同的products表,联结的条件是p2.prod_id=’DTNTR’和p1的vend_id和p2的vend_id相等。这两个表的联结,实际上就是一个表联结了它自己,因此形象地称这种联结方式为自联结。

外部联结

image.png
通过上图,我们可以更清晰地理解各种联结,其中外部联结包含左联结,右联结和完全联结。
为了更好地理解内部联结和外部联结,我们举两个例子:
SELECT customers.cust_id,orders.order_num FROM customers INNER JOIN orders ON customers.cust_id=orders.cust_id;
image.png
通过上例内部联结,检索出了下了订单的客户id和订单号。
SELECT customers.cust_id,orders.order_num FROM customers LEFT OUTER JOIN orders ON customers.cust_id=orders.cust_id;
image.png
通过比较发现左联结把左表(customers)的客户id全都列了出来 ,包含了未下订单客户的信息。
同理,若是右联结,则只能显示出已下订单的客户id。
SELECT customers.cust_id,orders.order_num FROM customers RIGHT OUTER JOIN orders ON customers.cust_id=orders.cust_id;
image.png
完全联结则展示了所有的数据。

组合查询

概念:组合查询(UNION)的功能是将多条SELECT语句集合起来,在一个结果中一并展示。
SQL1:SELECT vend_id,prod_id,prod_price FROM products WHERE prod_price<=5;
image.png
SQL2:SELECT vend_id,prod_id,prod_price FROM products WHERE vend_id IN (1001,1002);
image.png
SQL3:SELECT vend_id,prod_id,prod_price FROM products WHERE prod_price<=5 UNION SELECT vend_id,prod_id,prod_price FROM products WHERE vend_id IN (1001,1002);
image.png
直观地看UNION就是将两个返回结果拼接在了同一个结果中。

下面是 UNION 的使用规则:
● UNION必须由两条或两条以上的SELECT语句组成,语句之间用关键字UNION分隔
● UNION中的每个查询必须包含相同的列、表达式或聚集函数,但是各个列不需要以相同的次序列出
● 列数据类型必须兼容:类型不必完全相同,但必须是DBMS可以隐含地转换的类型
注意:

  1. UNION会默认取消重复的行,如果不想取消重复的行,则需要使用UNION ALL
  2. 使用WHERE子句完全可以达到和UNION一样的效果,但是当逻辑关系很复杂的时候,UNION的优势就会提现出来

如果要对组合查询进行排序,在用UNION组合查询时,只能使用一条ORDER BY子句,它必须出现在最后一条SELECT语句之后,如:
SELECT vend_id, prod_id, prod_price FROM products WHERE prod_price<=5 UNION SELECT vend_id, prod_id, prod_price FROM products WHERE vend_id IN (1001,1002) ORDER BY vend_id