Table: Person
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| PersonId | int |
| FirstName | varchar |
| LastName | varchar |
+-------------+---------+
PersonId is the primary key column for this table.
Table: Address
+-------------+---------+
| Column Name | Type |
+-------------+---------+
| AddressId | int |
| PersonId | int |
| City | varchar |
| State | varchar |
+-------------+---------+
AddressId is the primary key column for this table.
Write a SQL query for a report that provides the following information for each person in the Person table, regardless if(无论如何) there is an address for each of those people:
FirstName, LastName, City, State
无论地址是否存在,都输出每个Person,显然是左连接操作。
select FirstName, LastName, City, State
from Person left join Address on Person.PersonId = Address.PersonId;
表的连接方式大体分为:
- 内连接
- 外连接
- 交叉连接
假设有两个表A和B,内连接是A和B的交集,即输出的内容一定在A和B中都有的。而外连接除了A和B的交集,还有可能只存在于A或B的,只存在A而不存在B的,B列用null输出, 换句话说包括其中一个或者两个表的全集,如果另外一个表不满足连接条件,输出null。
等值连接是特殊的内连接,其连接条件是等于关系。而自然连接又是特殊的等值连接,它会去除重复属性。
外连接根据全集端不同,又分为左外连接(简称左连接),右外连接(简称右连接)和全连接。
mysql中使用join进行连接操作,默认为内连接。
下面用具体的实例看看不同的连接操作: 首先Person表内容为:
+----------+-----------+----------+
| PersonId | FirstName | LastName |
+----------+-----------+----------+
| 1 | Wang | Allen |
| 2 | Mary | John |
+----------+-----------+----------+
Address表:
+-----------+----------+----------+-----------+
| AddressId | PersonId | City | State |
+-----------+----------+----------+-----------+
| 1 | 2 | BeiJing | BeiJing |
| 2 | 5 | ShaoGuan | GuangDong |
+-----------+----------+----------+-----------+
mysql> select * from Person join Address on Person.PersonId = Address.PersonId;
+----------+-----------+----------+-----------+----------+---------+---------+
| PersonId | FirstName | LastName | AddressId | PersonId | City | State |
+----------+-----------+----------+-----------+----------+---------+---------+
| 2 | Mary | John | 1 | 2 | BeiJing | BeiJing |
+----------+-----------+----------+-----------+----------+---------+---------+
可见内连接只输出满足连接条件的行。
mysql> select * from Person left join Address on Person.PersonId = Address.PersonId;
+----------+-----------+----------+-----------+----------+---------+---------+
| PersonId | FirstName | LastName | AddressId | PersonId | City | State |
+----------+-----------+----------+-----------+----------+---------+---------+
| 2 | Mary | John | 1 | 2 | BeiJing | BeiJing |
| 1 | Wang | Allen | NULL | NULL | NULL | NULL |
+----------+-----------+----------+-----------+----------+---------+---------+
可见,左连接输出左边表的全集,不满足条件的右表输出NULL。
mysql> select * from Person right join Address on Person.PersonId = Address.PersonId;
+----------+-----------+----------+-----------+----------+----------+-----------+
| PersonId | FirstName | LastName | AddressId | PersonId | City | State |
+----------+-----------+----------+-----------+----------+----------+-----------+
| 2 | Mary | John | 1 | 2 | BeiJing | BeiJing |
| NULL | NULL | NULL | 2 | 5 | ShaoGuan | GuangDong |
+----------+-----------+----------+-----------+----------+----------+-----------+
结果不言而喻。
mysql不直接支持全连接,可以分别左连接、右连接,然后求并集实现
mysql> select * from Person left join Address on Person.PersonId = Address.PersonId
union
(select * from Person right join Address on Person.PersonId = Address.PersonId);
+----------+-----------+----------+-----------+----------+----------+-----------+
| PersonId | FirstName | LastName | AddressId | PersonId | City | State |
+----------+-----------+----------+-----------+----------+----------+-----------+
| 2 | Mary | John | 1 | 2 | BeiJing | BeiJing |
| 1 | Wang | Allen | NULL | NULL | NULL | NULL |
| NULL | NULL | NULL | 2 | 5 | ShaoGuan | GuangDong |
+----------+-----------+----------+-----------+----------+----------+-----------+
交叉连接相当于无连接条件,左右一一连接,形成笛卡尔积。若|A| = n, |B| = m 则 |A cross join B| = n * m
mysql> select * from Person cross join Address;
+----------+-----------+----------+-----------+----------+----------+-----------+
| PersonId | FirstName | LastName | AddressId | PersonId | City | State |
+----------+-----------+----------+-----------+----------+----------+-----------+
| 1 | Wang | Allen | 1 | 2 | BeiJing | BeiJing |
| 2 | Mary | John | 1 | 2 | BeiJing | BeiJing |
| 1 | Wang | Allen | 2 | 5 | ShaoGuan | GuangDong |
| 2 | Mary | John | 2 | 5 | ShaoGuan | GuangDong |
+----------+-----------+----------+-----------+----------+----------+-----------+
自然连接是除去重复属性的等值连接。
两者之间的区别和联系如下:
-
自然连接一定是等值连接,但等值连接不一定是自然连接。等值连接不把重复的属性除去;而自然连接要把重复的属性除去。
-
等值连接要求相等的分量,不一定是公共属性;而自然连接要求相等的分量必须是公共属性。