创建高级联结:
如何使用表别名?如何对被联结的表使用聚集函数?
使用表别名:SQL除了可以对列名和计算字段使用别名,还允许给表名起别名。这样做有两个主要理由:
缩短SQL语句;
允许在一条SELECT语句中多次使用相同的表。
mysql> SELECT cust_name, cust_contact -> FROM customers AS C, orders AS O, orderitems AS OI -> WHERE C.cust_id = O.cust_id AND OI.order_num = O.order_num AND prod_id = 'RGAN01'; +---------------+--------------------+ | cust_name | cust_contact | +---------------+--------------------+ | Fun4All | Denise L. Stephens | | The Toy Store | Kim Howard | +---------------+--------------------+ 2 rows in set (0.77 sec)
在这个例子中,可以看到在WHERE子句中使用完全限定列名,表名可以简写,缩短了SQL语句;可以看到这里表别名只用于WHERE子句。其实它不仅能用于WHERE子句,还可以用于SELECT的列表、 ORDER BY子句以及其他语句部分。
mysql> 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 = 'RGAN01'; +---------------+--------------------+ | cust_name | cust_contact | +---------------+--------------------+ | Fun4All | Denise L. Stephens | | The Toy Store | Kim Howard | +---------------+--------------------+ 2 rows in set (0.00 sec) # 上面是未使用表别名的,下面使用表别名后再就不能直接使用表名来进行完全限定列名了,会报错,只能用别名来完全限定列名 mysql> SELECT cust_name, cust_contact -> FROM customers AS C, orders AS O, orderitems AS OI -> WHERE customers.cust_id = orders.cust_id AND orderitems.order_num = orders.order_num AND prod_id = 'RGAN01'; ERROR 1054 (42S22): Unknown column 'customers.cust_id' in 'where clause'
不同类型的联结:内联结, 等值联结,自联结,自然联结, 外联结
自联结:
使用表别名的一个主要原因是能在一条SELECT语句中不止一次引用相同的表。(当然啦,不使用表别名也可以多次引用相同的表,只不过表面太长,比较麻烦而已)
假如要给与Jim Jones同一公司的所有顾客发送一封信件。 这个查询要求首先找出Jim Jones工作的公司, 然后找出在该公司工作的顾客。 下面是解决此问题的一种方法:
mysql> SELECT cust_id, cust_name, cust_contact -> FROM customers -> WHERE cust_name = (SELECT cust_name FROM customers WHERE cust_contact = 'Jim Jones'); +------------+-----------+--------------------+ | cust_id | cust_name | cust_contact | +------------+-----------+--------------------+ | 1000000003 | Fun4All | Jim Jones | | 1000000004 | Fun4All | Denise L. Stephens | +------------+-----------+--------------------+ 2 rows in set (0.05 sec) # 上述使用子查询,下面是使用联结的相同查询: mysql> SELECT c1.cust_id, c1.cust_name, c1.cust_contact -> FROM customers AS c1, customers AS c2 -> WHERE c1.cust_name = c2.cust_name AND c2.cust_contact = 'Jim Jones'; +------------+-----------+--------------------+ | cust_id | cust_name | cust_contact | +------------+-----------+--------------------+ | 1000000003 | Fun4All | Jim Jones | | 1000000004 | Fun4All | Denise L. Stephens | +------------+-----------+--------------------+ 2 rows in set (0.00 sec) # 尝试不使用表别名 mysql> SELECT cust_id, cust_name, cust_contact -> FROM customers -> WHERE cust_contact = 'Jim Jones'; +------------+-----------+--------------+ | cust_id | cust_name | cust_contact | +------------+-----------+--------------+ | 1000000003 | Fun4All | Jim Jones | +------------+-----------+--------------+ 1 row in set (0.00 sec) mysql> SELECT cust_id, cust_name, cust_contact -> FROM customers -> WHERE customers.cust_name = customers.cust_name AND cust_contact = 'Jim J ones'; +------------+-----------+--------------+ | cust_id | cust_name | cust_contact | +------------+-----------+--------------+ | 1000000003 | Fun4All | Jim Jones | +------------+-----------+--------------+ 1 row in set (0.00 sec)
此查询中需要的两个表实际上是相同的表,因此Customers表在FROM子句中出现了两次。虽然这是完全合法的,但如果直接对Customers进行多个引用会具有歧义性,因为DBMS不知道你引用的是哪个Customers表。 因此要解决此问题,需要使用表别名。Customers第一次出现用了别名C1, 第二次出现用了别名C2。现在可以将这些别名用作表名。例如,SELECT语句使用C1前缀明确给出所需列的全名。如果不这样,DBMS将返回错误,因为名为cust_id、cust_name、cust_contact的列各有两个。DBMS不知道想要的是哪一列( 即使它们其实是同一列)。WHERE首先联结两个表,然后按第二个表中的cust_contact过滤数据,返回所需的数据。
自联结通常作为外部语句,用来替代从相同表中检索数据的使用子查询语句。虽然最终的结果是相同的,但许多DBMS处理联结远比处理子查询快得多。建议使用自联结。
自然联结:自然连接排除列多次出现的情况,使每一列只返回一次。
mysql> SELECT C.*, O.order_num, O.order_date, OI.prod_id, OI.quantity, OI.item_price -> FROM customers AS C, orders AS O, orderitems AS OI -> WHERE C.cust_id = O.cust_id AND OI.order_num = O.order_num AND prod_id ="RGAN01";
我们迄今为止建立的每个内联结都是自然联结, 很可能永远都不会用到不是自然联结的内联结。
外联结:许多联结将一个表中的行与另一个表中的行相关联, 但有时候需要包含没有关联行的那些行。如果联结包含了那些在相关表中没有关联行的行,这种联结称为外联结。
mysql> SELECT customers.cust_id, orders.order_num -> FROM customers INNER JOIN orders ON customers.cust_id = orders.cust_id; +------------+-----------+ | cust_id | order_num | +------------+-----------+ | 1000000001 | 20005 | | 1000000001 | 20009 | | 1000000003 | 20006 | | 1000000004 | 20007 | | 1000000005 | 20008 | +------------+-----------+ 5 rows in set (0.03 sec) # 上面的是一个简单的内联结,它检索所有顾客及其订单,下面的是外联结,检索包括没有订单顾客在内的所有顾客。 mysql> SELECT customers.cust_id, orders.order_num -> FROM customers LEFT OUTER JOIN orders ON customers.cust_id = orders.cust_id; +------------+-----------+ | cust_id | order_num | +------------+-----------+ | 1000000001 | 20005 | | 1000000001 | 20009 | | 1000000002 | NULL | | 1000000003 | 20006 | | 1000000004 | 20007 | | 1000000005 | 20008 | +------------+-----------+ 6 rows in set (0.00 sec)
表名 INNER JOIN 表名 ON 等值联结条件
表名 LEFT OUTER JOIN 表名 ON 等值联结条件