16.1 使用表別名
別名除了用於列名和計算字段外, 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='TNT2';
+----------------+--------------+
| cust_name | cust_contact |
+----------------+--------------+
| Coyote Inc. | Y Lee |
| Yosemite Place | Y Sam |
+----------------+--------------+
- 分析:可以看到,
FROM
子句中3個表全都具有別名。customers AS c
建立c
作爲customers
的別名,等等。這使得能使用省寫的c
而不是全名customers
。在此例子中,表別名只用於WHERE
子句。但是,表別名不僅能用於WHERE
子句,它還可以用於SELECT
的列表、ORDER BY
子句以及語句的其他部分。
16.2 使用不同類型的聯結
16.2.1 自聯結
mysql> 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'
-> ;
+---------+----------------+
| prod_id | prod_name |
+---------+----------------+
| DTNTR | Detonator |
| FB | Bird seed |
| FC | Carrots |
| SAFE | Safe |
| SLING | Sling |
| TNT1 | TNT (1 stick) |
| TNT2 | TNT (5 sticks) |
+---------+----------------+
- 分析:此查詢中需要的兩個表實際上是相同的表,因此
products
表在FROM
子句中出現了兩次。雖然這是完全合法的,但對products
的引用具有二義性,因爲MySQL不知道你引用的是products
表中的哪個實例。
用自聯結而不用子查詢:自聯結通常作爲外部語句用來替代從相同表中檢索數據時使用的子查詢語句。雖然最終的結果是相同的,但有時候處理聯結遠比處理子查詢快得多。
16.2.2 自然聯結
自然聯結排除多次出現,使每個列只返回一次。
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 = 'FB';
+---------+-------------+----------------+-----------+------------+----------+--------------+--------------+-----------------+-----------+---------------------+---------+----------+------------+
| cust_id | cust_name | cust_address | cust_city | cust_state | cust_zip | cust_country | cust_contact | cust_email | order_num | order_date | prod_id | quantity | item_price |
+---------+-------------+----------------+-----------+------------+----------+--------------+--------------+-----------------+-----------+---------------------+---------+----------+------------+
| 10001 | Coyote Inc. | 200 Maple Lane | Detroit | MI | 44444 | USA | Y Lee | ylee@coyote.com | 20005 | 2005-09-01 00:00:00 | FB | 1 | 10.00 |
| 10001 | Coyote Inc. | 200 Maple Lane | Detroit | MI | 44444 | USA | Y Lee | ylee@coyote.com | 20009 | 2005-10-08 00:00:00 | FB | 1 | 10.00 |
+---------+-------------+----------------+-----------+------------+----------+--------------+--------------+-----------------+-----------+---------------------+---------+----------+------------+
- 分析:在這個例子中,通配符只對第一個表使用。所有其他列明確列出,所以沒有重複的列被檢索出來。
16.2.3 外部聯結
許多聯結將一個表中的行與另一個表中的行相關聯。但有時候會需要包含沒有關聯行的那些行。
爲了檢索所有客戶,包括那些沒有訂單的客戶,可如下進行:
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 |
+---------+-----------+
| 10001 | 20005 |
| 10001 | 20009 |
| 10002 | NULL |
| 10003 | 20006 |
| 10004 | 20007 |
| 10005 | 20008 |
+---------+-----------+
- 分析:類似於上一章中所看到的內部聯結,這條SELECT語句使用了關鍵字OUTER JOIN來指定聯結的類型(而不是在WHERE子句中指定)。但是,與內部聯結關聯兩個表中的行不同的是,外部聯結還包括沒有關聯行的行。在使用OUTER JOIN語法時,必須使用RIGHT或LEFT關鍵字指定包括其所有行的表( RIGHT指出的是OUTER JOIN右邊的表,而LEFT指出的是OUTER JOIN左邊的表)。 上面的例子使用LEFT OUTER JOIN從FROM子句的左邊表(customers表)中選擇所有行。
16.3 使用帶聚集函數的聯結
如果要檢索所有客戶及每個客戶所下的訂單數,下面使用了COUNT()函數的代碼可完成此工作:
mysql> SELECT customers.cust_name, customers.cust_id, COUNT(orders.order_num) AS num_ord FROM customers INNER JOIN orders ON customers.cust_id = orders.cust_id GROUP BY customers.cust_id;
+----------------+---------+---------+
| cust_name | cust_id | num_ord |
+----------------+---------+---------+
| Coyote Inc. | 10001 | 2 |
| Wascals | 10003 | 1 |
| Yosemite Place | 10004 | 1 |
| E Fudd | 10005 | 1 |
+----------------+---------+---------+
- 分析:此SELECT語句使用INNER JOIN將customers和orders表互相關聯。GROUP BY 子 句 按 客 戶 分 組 數 據 , 因 此 , 函 數 調 用COUNT(orders.order_num)對每個客戶的訂單計數,將它作爲num_ord返回。
mysql> 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;
+----------------+---------+---------+
| cust_name | cust_id | num_ord |
+----------------+---------+---------+
| Coyote Inc. | 10001 | 2 |
| Mouse House | 10002 | 0 |
| Wascals | 10003 | 1 |
| Yosemite Place | 10004 | 1 |
| E Fudd | 10005 | 1 |
+----------------+---------+---------+
- 分析:這個例子使用左外部聯結來包含所有客戶,甚至包含那些沒有任何下訂單的客戶。結果顯示也包含了客戶Mouse House,它有0個訂單。