说明
MySQL中的连接及其语法是MySQL中的重要部分,要理解连接,需要了解关系表中的一些基础知识。假设有一个包含产品目录信息的数据库表,其中每种类别的物品占一行,存储的消息包括产品描述和价格,以及生产该产品的供应商信息。现在假如有多个产品是由同一供应商生产的,那么这些供应商的信息应该存储在何处?如果和产品信息放在一起,那么必然会出现同一张表中重复存储了相同的供应商信息(不同产品),此外,如果供应商信息改变,那么每次改动都要改动多次,还要保证重复数据的一致性,这些都是不利于我们组织管理数据的地方,因此针对数据分表就是个比较好的方案。
在上面的例子中,我们可以建立两个表,产品信息表(products)和供应商信息表(vendors),vendors
表中存储所有供应商的信息,每个供应商占一行,并且每个供应商具有唯一的ID作为主键,products
表中存储所有产品的信息,此外对于每个产品只保存其对应的供应商ID作为外键,需要查询对应产品的供应商信息时通过产品信息表中的供应商ID去供应商表中来查询,这样做的好处是不会重复存储供应商信息,节省了空间和时间,另外供应商信息变动时无需更改产品信息表,也由于没有重复数据,在使用维护上更加方便。
上面的例子同时也说明了在关系型数据库中,合理的设计和组织数据存储形式可以大大地增加数据库的可扩展性,这也是关系型数据库的优势之一。
针对上面的例子,products
表数据如下:
mysql> SELECT * FROM products;
+---------+---------+----------------+------------+----------------------------------------------------------------+
| prod_id | vend_id | prod_name | prod_price | prod_desc |
+---------+---------+----------------+------------+----------------------------------------------------------------+
| ANV01 | 1001 | .5 ton anvil | 5.99 | .5 ton anvil, black, complete with handy hook |
| ANV02 | 1001 | 1 ton anvil | 9.99 | 1 ton anvil, black, complete with handy hook and carrying case |
| ANV03 | 1001 | 2 ton anvil | 14.99 | 2 ton anvil, black, complete with handy hook and carrying case |
| DTNTR | 1003 | Detonator | 13.00 | Detonator (plunger powered), fuses not included |
| FB | 1003 | Bird seed | 10.00 | Large bag (suitable for road runners) |
| FC | 1003 | Carrots | 2.50 | Carrots (rabbit hunting season only) |
| FU1 | 1002 | Fuses | 3.42 | 1 dozen, extra long |
| JP1000 | 1005 | JetPack 1000 | 35.00 | JetPack 1000, intended for single use |
| JP2000 | 1005 | JetPack 2000 | 55.00 | JetPack 2000, multi-use |
| OL1 | 1002 | Oil can | 8.99 | Oil can, red |
| SAFE | 1003 | Safe | 50.00 | Safe with combination lock |
| SLING | 1003 | Sling | 4.49 | Sling, one size fits all |
| TNT1 | 1003 | TNT (1 stick) | 2.50 | TNT, red, single stick |
| TNT2 | 1003 | TNT (5 sticks) | 10.00 | TNT, red, pack of 10 sticks |
+---------+---------+----------------+------------+----------------------------------------------------------------+
14 rows in set (0.00 sec)
vendors
表设计如下:
mysql> SELECT * FROM vendors;
+---------+----------------+-----------------+-------------+------------+----------+--------------+
| vend_id | vend_name | vend_address | vend_city | vend_state | vend_zip | vend_country |
+---------+----------------+-----------------+-------------+------------+----------+--------------+
| 1001 | Anvils R Us | 123 Main Street | Southfield | MI | 48075 | USA |
| 1002 | LT Supplies | 500 Park Street | Anytown | OH | 44333 | USA |
| 1003 | ACME | 555 High Street | Los Angeles | CA | 90046 | USA |
| 1004 | Furball Inc. | 1000 5th Avenue | New York | NY | 11111 | USA |
| 1005 | Jet Set | 42 Galaxy Road | London | NULL | N16 6PS | England |
| 1006 | Jouets Et Ours | 1 Rue Amusement | Paris | NULL | 45678 | France |
+---------+----------------+-----------------+-------------+------------+----------+--------------+
6 rows in set (0.00 sec)
内连接
内连接也称为等值连接,它连接要查询的两个表,基于两个表之间的相等测试进行检索,创建内部连接十分简单,如下: SELECT vend_name, prod_name, prod_price FROM vendors, products WHERE vendors.vend_id = products.vend_id ORDER BY vend_name,prod_name
上面的语句连接了两张表,并使用WHERE
子句来确保正确连接,在这里WHERE
用来指示MySQL匹配vendors
表中的vend_id
和products
中的vend_id
,也就是说,在连接表时,MySQL实际上会将第一个表中的每一行与第二个表中的每一行进行匹配,满足匹配条件的会作为连接结果,如果不指定WHERE
子句来限制匹配条件,连接的结果会是两张表行数的乘积,也叫作笛卡尔积,往往不是我们想要的结果。
对于内连接,MySQL提供了专用的语法,如下:
mysql> SELECT vend_name, prod_name, prod_price FROM vendors INNER JOIN products ON vendors.vend_id = products.vend_id;
+-------------+----------------+------------+
| vend_name | prod_name | prod_price |
+-------------+----------------+------------+
| Anvils R Us | .5 ton anvil | 5.99 |
| Anvils R Us | 1 ton anvil | 9.99 |
| Anvils R Us | 2 ton anvil | 14.99 |
| LT Supplies | Fuses | 3.42 |
| LT Supplies | Oil can | 8.99 |
| 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 |
| Jet Set | JetPack 1000 | 35.00 |
| Jet Set | JetPack 2000 | 55.00 |
+-------------+----------------+------------+
14 rows in set (0.00 sec)
执行结果与上面使用WHERE
的一样