《SQL学习指南》中的第10章
1.4 外连接
在多表连接中,存在连接条件可能无法表中所有的行匹配的问题,例如当account表与customer表进行连接时,会存在account表中cust_id列值无法匹配customer表中的cust_id列值,内连接在无法匹配成功时,是不会将这条匹配失败的结果放入返回的结果集中,假如我们需要强调某个表,也就是某个表的所有行必须返回,这个表的行数决定了返回结果集的行数。
1)左外连接
关键词:left outer join & left join ,left指出了连接了左边的表决定结果集的行数,而右边只负责提供与之匹配的列值。
例子1.
1)查询所有的商业客户账户 ——这是内连接
SELECT a.account_id ,b.cust_id,b.`name`
FROM account a INNER JOIN business b
ON a.cust_id = b.cust_id;
结果如图所示:
2)查询所有的客户,但同时如果是商业客户,返回其客户名称。
SELECT a.account_id ,a.cust_id,b.`name`
FROM account a LEFT OUTER JOIN business b
ON a.cust_id = b.cust_id;
结果如图所示:
3)查询所有的客户,但同时如果是私人客户,返回其客户名称。
SELECT a.account_id ,a.cust_id,
CONCAT(i.fname,' ',i.lname) AS gustname
FROM account a INNER JOIN individual i
ON a.cust_id = i.cust_id;
结果如图所示:
2)右外连接
关键词:right outer join & rigth join ,同理right指出了连接了右的表决定结果集的行数,而左边只负责提供与之匹配的列值。
1)
SELECT c.cust_id , b.`name`
FROM customer c
RIGHT JOIN business b
ON c.cust_id = b.cust_id;
结果如下图所示
3)多表外连接
1)获取所有的账户列表,其中包含个人客户的姓名以及商业客户的企业名称
SELECT a.account_id,
CONCAT(i.fname,' ',i.lname) AS person_name,
b.`name` as business_name
FROM account a
LEFT JOIN individual i
ON a.cust_id = i.cust_id
LEFT JOIN business b
ON a.cust_id = b.cust_id ;
结果如下图所示
SELECT COUNT(*) FROM account a;
结果如下
上面多表进行外连接,以account为主表,去匹配individual表中用户,若匹配不成功,显示为null;再去匹配business表中用户,同理匹配不成功,显示为null.同时说明了外连接中,存在以哪个表为主表,所以主表的顺序是不可变,解决上一次笔记中的遗留问题:内连接与表的顺序无关,但是外连接要注意主表所在的位置。
通过子查询的方式实现上面的三个表同时进行的自连接:
SELECT indi.id, person_name,bussiness_name
FROM (
SELECT a.account_id AS id, CONCAT(i.fname,' ',i.lname) as person_name
FROM account a
LEFT JOIN individual i
ON a.cust_id = i.cust_id
) AS indi
INNER JOIN (
SELECT a.account_id AS id, b.`name` AS bussiness_name
FROM account a
LEFT JOIN business b
ON a.cust_id = b.cust_id
) AS busi
ON indi.id = busi.id;
结果如下图所示
4)自外连接
1)前面通过内连接实现的一个问题:获取雇员及其主管的信息
SELECT e.emp_id,CONCAT(e.fname,' ',e.lname) AS emp_name,
em.emp_id AS su_emp_id,CONCAT(em.fname,' ', em.lname) AS superior_name
FROM employee e
INNER JOIN employee em
ON e.superior_emp_id = em.emp_id;
结果如下图所示:
上面的结果由于是内连接的原因,雇员信息会缺失一条,因为总经理是最高级别职员,没有上级,所以匹配不成功,没有在结果集中显示。下面通过左连接的方式,可以解决这个问题。
SELECT e.emp_id,CONCAT(e.fname,' ',e.lname) AS emp_name,
em.emp_id AS su_emp_id,CONCAT(em.fname,' ', em.lname) AS superior_name
FROM employee e
LEFT JOIN employee em
ON e.superior_emp_id = em.emp_id;
结果如下图所示:
将上面的左连接更改成右连接,这时候就是获取每个主管的下属职员
SELECT e.emp_id,CONCAT(e.fname,' ',e.lname) AS emp_name,
em.emp_id AS su_emp_id,CONCAT(em.fname,' ', em.lname) AS superior_name
FROM employee e
RIGHT JOIN employee em
ON e.superior_emp_id = em.emp_id;
结果如下图所示:
当某个主管下面存在n个职员时,这样就会在该主管对应的数据增加n-1条数据,这也就是18个雇员,为什么查出的结果集中有28条数据的。