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关联。
+-------------+----------------+------------+
| 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...关键字明确指定联结的类型。
步骤:
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。
+----------------+------------+----------+
| 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表两次。
1、对每个客户下了多少订单进行计数,包括那些至今未下过订单的客户;(没下单的客户,在orders表中找不到对应的cust_id)。
2、列出所有产品及订购数量,包括没有人订购过的产品;
上述例子中,联结包含了那些在相关表中没有关联行的行。这样类型的联结叫做外部链接。
举例:
检索客户机及其订单号,包括没有订单的客户。
代码:
+---------+-----------+
| 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。
可以先使用联结查询,查询所有客户的订单及其订单号。
+----------------+---------+-----------+
| 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)
在结果上使用聚合函数
+----------------+---------+-------------------------+
| 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)
+----------------+---------+-------------------------+
| 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客户,也被检索出来。
例如,建立两个表,一个存储供应商信息,另外一个存储产品信息。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客户,也被检索出来。
相关文章推荐
- mysql创建每月执行一次的event
- MySQL必知必会笔记(五)事务处理 全球化和本地化(字符集和校对)
- MySQL for Mac 安装和基本操作
- 初探 MySQL 的 Binlog
- MySql数据库知识点
- mysql-5.6.26 主主复制
- mysql 服务器配置
- MySQL的预编译功能简述
- MySQL数据库中的日期相关函数整理
- MySQL并发控制
- Cobar使用文档(可用作MySQL大型集群解决方案)
- mysql 备份
- MySqlite基本操作
- 收藏一些mysql博客
- mysql批量上传数据
- mysqldump参数之-F
- MySQL必知必会笔记(四)存储过程 游标 触发器
- MySql 入门笔记整理
- mysql日期函数
- MySQL 获得当前日期时间(以及时间的转换)