13.1 使用表别名
在之前的例子中,我们用的都是用的列别名,SQL还允许给表名起别名。
13.2 使用不同类型的联结
我们在上一章使用的只是称为内部联结或等值联结( equijoin) 的简单联结,现在来看3种其他联结,它们分别是自联结、自然联结和外部联结。
13.2.1 自联结
这里的自联结通俗来讲就是表自己与自己联结,此时表别名就发挥作用了。
我们看一个例子:
发现某物品(其ID为DTNTR)存在问题,因此想知道生产该物品的供应商生产的其他物品是否也存在这些问题。此查询要求首先找到生产ID为DTNTR的物品的供应商,然后找出这个供应商生产的其他物品。
一方面,我们可以用子查询来实现。
SELECT prod_id, prod_name FROM products WHERE vend_id = ( SELECT vend_id FROM products WHERE prod_id = 'DTNTR' );
另一方面,我们可以用自联结来实现。
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' );
此查询中需要的两个表实际上是相同的表,因此products表在FROM子句中出现了两次。 但对products 的引用具有二义性 。为解决此问题,使用了表别名。products的第一次出现为别名p1, 第二次出现为别名p2。
13.2.2 自然联结
对表进行联结,应该至少有一个列出现在不止一个表中(被联结的列)。标准的联结(内部联结)返回所有数据,甚至相同的列多次出现。 自然联结排除多次出现,使每个列只返回一次。
自然联结是这样一种联结,其中你只能选择那些唯一的列。这一般是通过对表使用通配符(SELECT *),对所有其他表的列使用明确的子集来完成的。
13.2.3 外联结
许多联结将一个表中的行与另一个表中的行相关联。但有时候会需要包含没有关联行的那些行。
看这样一个例子:
下面的SELECT语句给出一个简单的内部联结。它检索所有客户及其订单:
SELECT customers.cust_id, orders.order_num FROM customers INNER JOIN orders ON customers.cust_id = orders.cust_id;
但是,为了检索所有客户,包括那些没有订单的客户, 就要使用外部联结
SELECT customers.cust_id, orders.order_num FROM customers LEFT ORTER JOIN orders ON customers.cust_id = orders.cust_id;
与内部联结关联两个表中的行不同的是,外部联结还包括没有关联行的行。在使用OUTER JOIN语法时,必须使用RIGHT或LEFT关键字 指定包括其所有行的表(RIGHT指出的是OUTER JOIN右边的表,而LEFT 指出的是OUTER JOIN左边的表)。上面的例子使用LEFT OUTER JOIN从FROM子句的左边表(customers表)中选择所有行。为了从右边的表中选择所有行,应该使用RIGHT OUTER JOIN
13.3 使用带聚集函数的联结
我们来看一个COUNT()函数的例子吧
要检索所有客户及每个客户所下的订单数
SELECT customers.cust_name customers.cust_id, COUNT(orders.order_num) AS num_ord FROM customers LINNER JOIN orders ON customers.cust_id = orders.cust_id;
结果是这样的:
13.4 使用联结和联结条件
- 注意所使用的联结类型。一般我们使用内部联结,但使用外部联结也是有效的。
- 保证使用正确的联结条件,否则将返回不正确的数据。
- 应该总是提供联结条件,否则会得出笛卡儿积。
- 在一个联结中可以包含多个表,甚至对于每个联结可以采用不同的联结类型。虽然这样做是合法的,一般也很有用,但应该在一起测试它们前,分别测试每个联结。这将使故障排除更为简单。