01、 一个案例引发的多表连接
1.1、案例说明
从多个表中获取数据:
SELECT employee_id,department_name
FROM employees,departments;
SELECT *
FROM employees;
SELECT *
FROM departments;
SELECT 107*27 FROM dual;
我们把上述多表查询中出现的问题称为:笛卡尔积的错误。 错误的原因:缺少了多表的连接条件
1.2、 笛卡尔积的理解
- 笛卡尔乘积是一个数学运算。假设我有两个集合 X 和 Y,那么 X 和 Y 的笛卡尔积就是 X 和 Y 的所有可能组合,也就是第一个对象来自于 X,第二个对象来自于 Y 的所有可能。
组合的个数即为两个集合中元素个数的乘积数。 - SQL92中,笛卡尔积也称为
交叉连接 ,英文是 CROSS JOIN 。在 SQL99 中也是使用 CROSS JOIN表示交叉连接。它的作用就是可以把任意表进行连接,即使这两张表不相关。
1.3、案例分析与问题解决
笛卡尔积的错误会在下面条件下产生:
- 省略多个表的连接条件(或关联条件)
- 连接条件(或关联条件)无效
- 所有表中的所有行互相连接
为了避免笛卡尔积, 可以在 WHERE 加入有效的连接条件。
SELECT employee_id,department_name
FROM employees,departments
WHERE employees.`department_id` = departments.department_id;
SELECT employees.employee_id,departments.department_name,employees.department_id
FROM employees,departments
WHERE employees.`department_id` = departments.department_id;
SELECT emp.employee_id,dept.department_name,emp.department_id
FROM employees emp,departments dept
WHERE emp.`department_id` = dept.department_id;
SELECT emp.employee_id,departments.department_name,emp.department_id
FROM employees emp,departments dept
WHERE emp.`department_id` = departments.department_id;
SELECT emp.`employee_id`,emp.`last_name`,dept.`department_name`,loc.`city`
FROM employees emp,departments dept,locations loc
WHERE emp.`department_id` = dept.`department_id`
AND dept.`location_id` = loc.`location_id`;
02、多表查询
2.1、等值连接 vs 非等值连接
案例
7.1 等值连接 vs 非等值连接
SELECT e.`last_name`,e.`salary`,j.`grade_level`
FROM `employees` e,`job_grades` j
WHERE e.`salary` BETWEEN j.`lowest_sal`AND j.`highest_sal`;
2.2、自连接 vs 非自连接
当table1和table2本质上是同一张表,只是用取别名的方式虚拟成两张表以代表不同的意义。然后两个表再进行内连接,外连接等查询。
案例
SELECT emp.employee_id,emp.last_name,mgr.employee_id,mgr.last_name
FROM employees emp ,employees mgr
WHERE emp.`manager_id` = mgr.`employee_id`;
2.3、内连接 vs 外连接
- 内连接: 合并具有同一列的两个以上的表的行,
结果集中不包含一个表与另一个表不匹配的行 - 外连接: 两个表在连接过程中除了
返回满足连接条件的行以外还返回左(或右)表中不满足条件的行 , 这种连接称为左(或右) 外连接。没有匹配的行时, 结果表中相应的列为空(NULL)。 - 如果是左外连接,则连接条件中左边的表也称为 主表 ,右边的表称为 从表 。
- 如果是右外连接,则连接条件中右边的表也称为 主表 ,左边的表称为 从表 。
SELECT employee_id,department_name
FROM employees e,departments d
WHERE e.`department_id` = d.department_id;
SELECT employee_id,department_name
FROM employees e,departments d
WHERE e.`department_id` = d.department_id;
SELECT employee_id,department_name
FROM employees e,departments d
WHERE e.`department_id` = d.department_id(+);
03、SQL99语法实现多表查询
3.1、基本语法
使用JOIN…ON子句创建连接的语法结构:
SELECT table1.column, table2.column,table3.column
FROM table1
JOIN table2 ON table1 和 table2 的连接条件
JOIN table3 ON table2 和 table3 的连接条件
3.2 内连接的实现
SELECT 字段列表
FROM A表 INNER JOIN B表
ON 关联条件
WHERE 等其他子句;
SELECT e.last_name,d.department_name
FROM employees e INNER JOIN departments d
ON e.`department_id` = d.department_id;
SELECT e.last_name,d.department_name,l.city
FROM employees e JOIN departments d
ON e.`department_id` = d.department_id
JOIN locations l
ON d.`location_id` = l.`location_id`;
3.3 外连接( OUTER JOIN)的实现
3.3.1 左外连接(LEFT OUTER JOIN)
SELECT 字段列表
FROM A表 LEFT JOIN B表
ON 关联条件
WHERE 等其他子句;
SELECT last_name,department_name
FROM employees e LEFT OUTER JOIN departments d
ON e.`department_id` = d.`department_id`;
3.3.2 右外连接(RIGHT OUTER JOIN)
SELECT 字段列表
FROM A表 RIGHT JOIN B表
ON 关联条件
WHERE 等其他子句;
SELECT last_name,department_name
FROM departments d RIGHT OUTER JOIN employees e
ON e.`department_id` = d.`department_id`;
3.3.3 满外连接(FULL OUTER JOIN)
- 满外连接的结果 = 左右表匹配的数据 + 左表没有匹配到的数据 + 右表没有匹配到的数据。
- SQL99是支持满外连接的。使用FULL JOIN 或 FULL OUTER JOIN来实现。
- 需要注意的是,MySQL不支持FULL JOIN,但是可以用 LEFT JOIN UNION RIGHT join代替。
SELECT last_name,department_name
FROM departments d FULL OUTER JOIN employees e
ON e.`department_id` = d.`department_id`;
04、UNION的使用
UNION和UNION ALL的使用
- UNION:会执行去重的操作
- UNION ALL :不会执行去重的操作
- 结论:如果明确知道合并数据后的结果数据不存在重复数据,或者不需要去除重复的数据,
则尽量使用UNION ALL语句,以提高数据查询的效率。
05、7种SQL JOINS的实现(重点!!!)
SELECT employee_id,department_name
FROM employees e JOIN departments d
ON e.`department_id` = d.`department_id`;
SELECT employee_id,department_name
FROM employees e LEFT JOIN departments d
ON e.`department_id` = d.`department_id`;
SELECT employee_id,department_name
FROM employees e RIGHT JOIN departments d
ON e.`department_id` = d.`department_id`;
SELECT employee_id,department_name
FROM employees e LEFT JOIN departments d
ON e.`department_id` = d.`department_id`
WHERE d.`department_id` IS NULL;
SELECT employee_id,department_name
FROM employees e RIGHT JOIN departments d
ON e.`department_id` = d.`department_id`
WHERE e.`department_id` IS NULL;
SELECT employee_id,department_name
FROM employees e LEFT JOIN departments d
ON e.`department_id` = d.`department_id`
UNION ALL
SELECT employee_id,department_name
FROM employees e RIGHT JOIN departments d
ON e.`department_id` = d.`department_id`
WHERE e.`department_id` IS NULL;
SELECT employee_id,department_name
FROM employees e LEFT JOIN departments d
ON e.`department_id` = d.`department_id`
WHERE d.`department_id` IS NULL
UNION ALL
SELECT employee_id,department_name
FROM employees e RIGHT JOIN departments d
ON e.`department_id` = d.`department_id`;
SELECT employee_id,department_name
FROM employees e LEFT JOIN departments d
ON e.`department_id` = d.`department_id`
WHERE d.`department_id` IS NULL
UNION ALL
SELECT employee_id,department_name
FROM employees e RIGHT JOIN departments d
ON e.`department_id` = d.`department_id`
WHERE e.`department_id` IS NULL;
06、SQL99语法新特性
6.1、自然连接
NATURAL JOIN : 它会帮你自动查询两张连接表中所有相同的字段 ,然后进行等值连接 。
SELECT employee_id,last_name,department_name
FROM employees e JOIN departments d
ON e.`department_id` = d.`department_id`
AND e.`manager_id` = d.`manager_id`;
SELECT employee_id,last_name,department_name
FROM employees e NATURAL JOIN departments d;
6.2、USING连接
当我们进行连接的时候,SQL99还支持使用 USING 指定数据表里的 同名字段 进行等值连接。但是只能配合JOIN一起使用。
SELECT employee_id,last_name,department_name
FROM employees e JOIN departments d
ON e.department_id = d.department_id;
SELECT employee_id,last_name,department_name
FROM employees e JOIN departments d
USING (department_id);
07、拓展
- WHERE:适用于所有关联查询
- ON :只能和JOIN一起使用,只能写关联条件。虽然关联条件可以并到WHERE中和其他条件一起写,但分开写可读性更好。
- USING:只能和JOIN一起使用,而且要求两个关联字段在关联表中名称一致,而且只能表示关联字段值相等
注意: 我们要 控制连接表的数量 。多表连接就相当于嵌套 for 循环一样,非常消耗资源,会让 SQL 查询性能下降得很严重,因此不要连接不必要的表。在许多 DBMS 中,也都会有最大连接表的限制。
SELECT last_name,job_title,department_name
FROM employees INNER JOIN departments INNER JOIN jobs
ON employees.department_id = departments.department_id
AND employees.job_id = jobs.job_id;
08、本章练习
SELECT e.last_name,e.department_id,d.department_name
FROM employees e LEFT OUTER JOIN departments d
ON e.`department_id` = d.`department_id`;
SELECT e.job_id,d.location_id
FROM employees e JOIN departments d
ON e.`department_id` = d.`department_id`
WHERE d.`department_id` = 90;
DESC departments;
SELECT e.last_name ,e.`commission_pct`, d.department_name , d.location_id , l.city
FROM employees e LEFT JOIN departments d
ON e.`department_id` = d.`department_id`
LEFT JOIN locations l
ON d.`location_id` = l.`location_id`
WHERE e.`commission_pct` IS NOT NULL;
SELECT *
FROM employees
WHERE commission_pct IS NOT NULL;
SELECT e.last_name , e.job_id , e.department_id , d.department_name
FROM employees e JOIN departments d
ON e.`department_id` = d.`department_id`
JOIN locations l
ON d.`location_id` = l.`location_id`
WHERE l.`city` = 'Toronto';
SELECT e.last_name , e.job_id , e.department_id , d.department_name
FROM employees e,departments d ,locations l
WHERE e.`department_id` = d.`department_id`
AND d.`location_id` = l.`location_id`
AND l.`city` = 'Toronto';
SELECT d.department_name,l.street_address,e.last_name,e.job_id,e.salary
FROM departments d LEFT JOIN employees e
ON e.`department_id` = d.`department_id`
LEFT JOIN locations l
ON d.`location_id` = l.`location_id`
WHERE d.`department_name` = 'Executive';
DESC departments;
DESC locations;
employees Emp
kochhar 101 king 100
SELECT emp.last_name "employees",emp.employee_id "Emp#",mgr.last_name "manager", mgr.employee_id "Mgr#"
FROM employees emp LEFT JOIN employees mgr
ON emp.manager_id = mgr.employee_id;
SELECT d.department_id
FROM departments d LEFT JOIN employees e
ON d.`department_id` = e.`department_id`
WHERE e.`department_id` IS NULL;
SELECT l.location_id,l.city
FROM locations l LEFT JOIN departments d
ON l.`location_id` = d.`location_id`
WHERE d.`location_id` IS NULL;
SELECT department_id
FROM departments
WHERE department_id IN (1000,1100,1200,1300,1600);
SELECT e.employee_id,e.last_name,e.department_id
FROM employees e JOIN departments d
ON e.`department_id` = d.`department_id`
WHERE d.`department_name` IN ('Sales','IT');
以上是MySQL基础篇的多表查询,本章的知识内容来源于尚硅谷MySQL基础,按照视频教学顺序总结出来的。文章总结的若有不足,欢迎大家斧正。谢谢!
|