Chapter 13 ~ 14 创建高级联结及组合查询

创建高级联结:

 如何使用表别名?如何对被联结的表使用聚集函数?

 使用表别名: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_idcust_namecust_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 等值联结条件

你可能感兴趣的:(Chapter 13 ~ 14 创建高级联结及组合查询)