使用不同类型的联结
上次学到的是等值联结,也是最简单的联结。这次要学习其它三种联结:自联结,自然联结和外部联结。
自联结
id为10031的员工薪水漏发了,需要确认下这个部门的所有员工,利用自联结的方法找出该部门所有员工的emp_no
。
方案一: 子查询
SELECT emp_no FROM dept_emp WHERE dept_no = (SELECT dept_no FROM dept_emp WHERE emp_no = '10031') LIMIT 10
输出:
+--------+
| emp_no |
+--------+
| 10001 |
| 10006 |
| 10008 |
| 10012 |
| 10014 |
| 10018 |
| 10021 |
| 10022 |
| 10023 |
| 10025 |
+--------+
10 rows in set (0.00 sec)
通过子查询的方式把员工所在的id返回给了dept_no,最终查找出他所在部门的所有id。
方案二 自然联结
SELECT e1.emp_no FROM dept_emp AS e1, dept_emp AS e2 WHERE e1.dept_no = e2.dept_no AND e2.emp_no = 10031 LIMIT 10;
输出:
+--------+
| emp_no |
+--------+
| 10001 |
| 10006 |
| 10008 |
| 10012 |
| 10014 |
| 10018 |
| 10021 |
| 10022 |
| 10023 |
| 10025 |
+--------+
10 rows in set (0.00 sec)
分析:
所谓联结就是将两张或多张表进行结合,而自然联结的过程会将两张表的所有列合并起来。自联结的其实就是指对一张表与自己进行结合。
自然联结
例:
表A:
id | a | b |
---|---|---|
1 | 2 | 3 |
2 | 4 | 5 |
表B:
id | c | d |
---|---|---|
1 | 7 | 8 |
2 | 9 | 10 |
两表联结后本身应该是会形成笛卡尔积的形式,表A的每一行会去匹配表B的每一行:
id | a | b | id | c | d |
---|---|---|---|---|---|
1 | 2 | 3 | 1 | 7 | 8 |
1 | 2 | 3 | 2 | 9 | 10 |
2 | 4 | 5 | 1 | 7 | 8 |
2 | 4 | 5 | 2 | 9 | 10 |
经过WHERE a.id = b.id
去除了重复的一列id
,过滤掉了了a.id != b.id
的行,最终得到这样一张表:
id | a | b | c | d |
---|---|---|---|---|
1 | 2 | 3 | 7 | 8 |
2 | 4 | 5 | 9 | 10 |
外部联结
在做关联的时候如果需要包含到没有关联的行,这种类型可以称为外部联结。
外联结分为左外联结和右外联结:
左外联结:
SELECT employees.emp_no, titles.title FROM employees LEFT JOIN titles ON employees.emp_no = titles.emp_no;
左外联结指的是在对两张表做联结的时候匹配的不单单是双方共同的行,还会把左表中未与右表匹配的行也会结合进去。
举个例子来说:
A表有100行,包含该公司的所有员工。(员工id,员工姓名)
B表有80行,包含该公司的员工销售业绩。(员工id,销售情况)
这也就说明了100个员工中有80个是有业绩的,如果是做自然联结,最终只会匹配80个员工及其销售情况。但是左外联结会把没有业绩的员工也会进行结合。
由此得知:
右外联结就会和左外联结相反。
使用带聚集函数的联结
SELECT employees.emp_no,first_name,last_name, COUNT(salaries.salary) AS sal_num FROM employees INNER JOIN salaries ON employees.emp_no = salaries.emp_no GROUP BY employees.emp_no LIMIT 10;
输出:
+--------+------------+-----------+---------+
| emp_no | first_name | last_name | sal_num |
+--------+------------+-----------+---------+
| 10001 | Georgi | Facello | 17 |
| 10002 | Bezalel | Simmel | 6 |
| 10003 | Parto | Bamford | 7 |
| 10004 | Chirstian | Koblick | 16 |
| 10005 | Kyoichi | Maliniak | 13 |
| 10006 | Anneke | Preusig | 12 |
| 10007 | Tzvetan | Zielinski | 14 |
| 10008 | Saniya | Kalloufi | 3 |
| 10009 | Sumant | Peac | 18 |
| 10010 | Duangkaew | Piveteau | 6 |
+--------+------------+-----------+---------+
10 rows in set (0.00 sec)
使用联结和联结条件
- 注意所使用的联结类型,一般使用内部联结
- 保证所使用的的联结条件,否则将返回不正确的数据
- 应该总是提供联结条件,用来过滤掉笛卡尔积所产生的不必要的数据