您的位置:首页 > 数据库 > MySQL

Mysql联接查询-JOIN-从多个关联的表中查询数据

2015-08-11 15:36 204 查看
将要存储的信息分类存储在不同的表中,不同的表之间通过主键和外键关联,这样就构成了关系型数据库。

例如,建立两个表,一个存储供应商信息,另外一个存储产品信息。vendors表包含供应商信息,每个供应商占一行,每个供应商具有唯一标识,此标识被称为主键(primary key)。products表只存储产品信息,他除了存储供应商ID(vendors表主键)之外,不存储其他供应商的信息。vendors表的主键又叫做products表的外键,它将vendors表和products表关联起来,利用供应商ID能从vendors表找到供应商的详细信息。

外键,就是某一个表的一列,它包含另外一个表的主键值,定义了两个表之间的关系。

这样做的好处是:

1、供应商信息不重复,从而不浪费时间和空间;

2、如果供应商信息变动,可只修改vendors表的单个记录,相关表中的数据不用改动;

3、由于数据无重复,显然数据是一致的,这使得处理数据更简单。

内联结查询

从多个关联的表中查询数据。联结查询非常简单,只需要列出要检索的列以及表与表之间是如何关联的即可。

举例,查询每个供应商名字以及提供的商品价格和名称。

分析:

供应商名字存储在vendors表,商品名称和价格存储在products表。这两个表之间通过vend_id关联。

mysql> SELECT vend_name,prod_name,prod_price FROM vendors,products WHERE vendors.vend_id=products.vend_id ORDER BY vend_name;
结果:

+-------------+----------------+------------+

| vend_name | prod_name | prod_price |

+-------------+----------------+------------+

| ACME | Detonator | 13.00 |

| ACME | Bird seed | 10.00 |

| ACME | Carrots | 2.50 |

| ACME | Safe | 50.00 |

| ACME | Sling | 4.49 |

| ACME | TNT (1 stick) | 2.50 |

| ACME | TNT (5 sticks) | 10.00 |

| Anvils R Us | .5 ton anvil | 5.99 |

| Anvils R Us | 1 ton anvil | 9.99 |

| Anvils R Us | 2 ton anvil | 14.99 |

| Jet Set | JetPack 1000 | 35.00 |

| Jet Set | JetPack 2000 | 55.00 |

| LT Supplies | Fuses | 3.42 |

| LT Supplies | Oil can | 8.99 |

+-------------+----------------+------------+

14 rows in set (0.06 sec)

当列可能出现二义性的时候,必须使用完全限定列名,就如本例这样:vendors.vend_name。

上面这个例子所用的联结叫做等值联结或者叫内联结。对于这样联结,我们可以指定INNER JOIN...ON...关键字明确指定联结的类型。

mysql> SELECT vend_name,prod_name,prod_price FROM vendors INNER JOIN products ON vendors.vend_id=products.vend_id ORDER BY vend_name;


联结多个表无限制

联结查询对于表的数量是没有限制的。创建联结的规则也一样,首先列出要查询的表,然后定义表之间如何联结。

步骤:

1、列出所有表的表结构:DESC table_name

2、从表结构中,可以看到这些表中相同的列,这些表就是靠这些列关联起来的。

举例:

检索order_num=20005的订单中,包含的产品名称、产品数量、产品价格、已经供应商名称。

思路:

从本例中可以得知,这些信息分别存储在三个表中:orderitems、products、vendors。

通过DESC orderitems、DESC products、DESC vendors,可以得知他们可以通过这种关系联结:ordersitem.prod_id=products.prod_id AND products.vend_id=vendors.vend_id。

mysql> SELECT prod_name,prod_price,quantity FROM orderitems,products,vendors WHERE orderitems.prod_id=products.prod_id AND products.vend_id=vendors.vend_id AND
order_num=20005;
结果:

+----------------+------------+----------+

| prod_name | prod_price | quantity |

+----------------+------------+----------+

| .5 ton anvil | 5.99 | 10 |

| 1 ton anvil | 9.99 | 3 |

| TNT (5 sticks) | 10.00 | 5 |

| Bird seed | 10.00 | 1 |

+----------------+------------+----------+

4 rows in set (0.03 sec)

联结查询有时候能替代子查询。

自联结查询

自联结查询通常是替代从相同表中检索数据时使用的子查询,因为通常自联结查询比子查询要快速。

例如,我想知道生产DTNTR这个商品的供应商还生产了哪些商品。这就是典型的自联结应用。因为我们需要从products表中查询出vend_id,再根据vend_id从products表中查询该供应商的其他商品。整个查询中,没有涉及其他的表,只是使用了products表两次。

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';
此查询中需要的两个表实际上是相同的表,因此products表在FROM子句中出现两次。为了避免二义性,我们分别对第一次出现的products表指定了别名p1,对第二次出现的products表指定了别名p2。这些别名可以用在select子句中。

外联结查询

前面讲的内联结,指的是表与表之间都有对应的关联行。但是有的情况下,在另外一个表中找不到与此表对应的行。例如:

1、对每个客户下了多少订单进行计数,包括那些至今未下过订单的客户;(没下单的客户,在orders表中找不到对应的cust_id)。

2、列出所有产品及订购数量,包括没有人订购过的产品;

上述例子中,联结包含了那些在相关表中没有关联行的行。这样类型的联结叫做外部链接。

举例:

检索客户机及其订单号,包括没有订单的客户。

代码:

mysql> SELECT customers.cust_id,order_num FROM customers <strong>LEFT OUTER JOIN</strong> orders <strong>ON</strong> customers.cust_id=orders.cust_id;
结果:

+---------+-----------+

| cust_id | order_num |

+---------+-----------+

| 10001 | 20005 |

| 10001 | 20009 |

| 10002 | NULL |

| 10003 | 20006 |

| 10004 | 20007 |

| 10005 | 20008 |

+---------+-----------+

6 rows in set (0.08 sec)

从结果看到,10002这个客户还没有订购过任何商品。

此例使用了左外联结查询,即LEFT OUTER JOIN...ON...。该联结将返回‘LEFT OUTER JOIN’左边表中所有的行,而右边表如果没有对应的行则返回NULL。

我们也可以使用RIGHT OUTER JOIN...ON...,这样将返回‘RIGHT OUTER JOIN’右侧表中所有的行,而左边表如果没有对应的行则返回NULL。

带聚合函数的内联结

聚合函数可以和联结一起使用。例如要检索所有客户及其订单数。

可以先使用联结查询,查询所有客户的订单及其订单号。

mysql> SELECT customers.cust_name,customers.cust_id,orders.order_num FROM customers INNER JOIN orders ON customers.cust_id=orders.cust_id GROUP BY order_num;
结果是:

+----------------+---------+-----------+

| cust_name | cust_id | order_num |

+----------------+---------+-----------+

| Coyote Inc. | 10001 | 20005 |

| Wascals | 10003 | 20006 |

| Yosemite Place | 10004 | 20007 |

| E Fudd | 10005 | 20008 |

| Coyote Inc. | 10001 | 20009 |

+----------------+---------+-----------+

5 rows in set (0.10 sec)

在结果上使用聚合函数

mysql> SELECT customers.cust_name,customers.cust_id,COUNT(orders.order_num) FROM customers INNER JOIN orders ON customers.cust_id=orders.cust_id GROUP BY cust_i
d;
结果是:

+----------------+---------+-------------------------+

| cust_name | cust_id | COUNT(orders.order_num) |

+----------------+---------+-------------------------+

| Coyote Inc. | 10001 | 2 |

| Wascals | 10003 | 1 |

| Yosemite Place | 10004 | 1 |

| E Fudd | 10005 | 1 |

+----------------+---------+-------------------------+

4 rows in set (0.01 sec)

带聚合函数的外联结

将上面例子改成外联结:

mysql> SELECT customers.cust_name,customers.cust_id,COUNT(orders.order_num) FROM customers LEFT OUTER JOIN orders ON customers.cust_id=orders.cust_id GROUP BY c
ust_id;
结果是:

+----------------+---------+-------------------------+

| cust_name | cust_id | COUNT(orders.order_num) |

+----------------+---------+-------------------------+

| Coyote Inc. | 10001 | 2 |

| Mouse House | 10002 | 0 |

| Wascals | 10003 | 1 |

| Yosemite Place | 10004 | 1 |

| E Fudd | 10005 | 1 |

+----------------+---------+-------------------------+

5 rows in set (0.00 sec)

没有订单的10002客户,也被检索出来。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: