|
@@ -0,0 +1,276 @@
|
|
|
|
+#第六章、多表查询
|
|
|
|
+
|
|
|
|
+#1、熟悉教学常见的几个表
|
|
|
|
+DESC employees;
|
|
|
|
+
|
|
|
|
+DESC departments;
|
|
|
|
+
|
|
|
|
+DESC locations;
|
|
|
|
+
|
|
|
|
+#查询员工名为'Abel'的人在哪个城市工作?
|
|
|
|
+SELECT *
|
|
|
|
+FROM employees
|
|
|
|
+WHERE last_name = 'Abel';
|
|
|
|
+
|
|
|
|
+SELECT *
|
|
|
|
+FROM departments
|
|
|
|
+WHERE department_id = 80;
|
|
|
|
+
|
|
|
|
+SELECT *
|
|
|
|
+FROM locations
|
|
|
|
+WHERE location_id = 2500;
|
|
|
|
+
|
|
|
|
+#2、出现笛卡尔积的错误
|
|
|
|
+#错误的原因:缺少了多表的连接条件
|
|
|
|
+
|
|
|
|
+#错误的实现方式:每个员工都与每个部门匹配了一遍
|
|
|
|
+SELECT employee_id,department_name
|
|
|
|
+FROM employees,departments; #查询出2889条记录
|
|
|
|
+
|
|
|
|
+#错误的方式
|
|
|
|
+SELECT employee_id,department_name
|
|
|
|
+FROM employees CROSS JOIN departments; #查询出2889条记录
|
|
|
|
+
|
|
|
|
+SELECT *
|
|
|
|
+FROM employees;
|
|
|
|
+
|
|
|
|
+SELECT 2889/107
|
|
|
|
+FROM DUAL;
|
|
|
|
+
|
|
|
|
+SELECT *
|
|
|
|
+FROM departments;
|
|
|
|
+
|
|
|
|
+#3、多表查询的正确方式:需要有连接条件
|
|
|
|
+SELECT employee_id,department_name
|
|
|
|
+FROM employees,departments
|
|
|
|
+#两个表的连接条件
|
|
|
|
+WHERE employees.`department_id` = departments.department_id;
|
|
|
|
+
|
|
|
|
+#4、如果查询语句中出现了多个表中都存在的字段,则必须指明此字段所在的表。
|
|
|
|
+SELECT employees.employee_id,departments.department_name,employees.department_id
|
|
|
|
+FROM employees,departments
|
|
|
|
+WHERE employees.`department_id` = departments.`department_id`;
|
|
|
|
+
|
|
|
|
+#建议:从SQL优化的角度,建议多表查询时,每个字段前都指明其所在的表
|
|
|
|
+
|
|
|
|
+#5、可以给表起别名,在SELECT和WHERE中使用表的别名
|
|
|
|
+SELECT emp.employee_id,dept.department_name,emp.department_id
|
|
|
|
+FROM employees emp,departments dept
|
|
|
|
+WHERE emp.`department_id` = dept.department_id;
|
|
|
|
+
|
|
|
|
+#如果给表起了别名,一旦在SELECT或WHERE中使用表名的话,则必须使用表的别名,而不能再使用表的原名。
|
|
|
|
+#如下的操作是错误的:
|
|
|
|
+SELECT emp.employee_id,departments.department_name,emp.department_id
|
|
|
|
+FROM employees emp,departments dept
|
|
|
|
+WHERE emp.`department_id` = departments.department_id;
|
|
|
|
+
|
|
|
|
+#6、结论:如果有n个表实现多表的查询,则需要至少n-1个连接条件
|
|
|
|
+#练习:查询员工的employee_id,last_name,department_name,city
|
|
|
|
+SELECT e.employee_id,e.last_name,d.department_name,l.city,e.department_id,l.location_id
|
|
|
|
+FROM employees e,departments d,locations l
|
|
|
|
+WHERE e.`department_id` = d.`department_id` AND d.`location_id` = l.`location_id`;
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+演绎式:提出问题1 ---> 解决问题1 ---> 提出问题2 ---> 解决问题2 ...
|
|
|
|
+
|
|
|
|
+归纳式:总 -- 分
|
|
|
|
+*/
|
|
|
|
+
|
|
|
|
+#7、多表查询的分类
|
|
|
|
+/*
|
|
|
|
+角度1:等值连接 vs 非等值连接
|
|
|
|
+
|
|
|
|
+角度2:自连接 vs 非自连接
|
|
|
|
+
|
|
|
|
+角度3:内连接 vs 外连接
|
|
|
|
+*/
|
|
|
|
+
|
|
|
|
+#7.1、等值连接 vs 非等值连接
|
|
|
|
+#非等值连接的例子:
|
|
|
|
+SELECT *
|
|
|
|
+FROM job_grades;
|
|
|
|
+
|
|
|
|
+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`;
|
|
|
|
+WHERE e.`salary` >= j.`lowest_sal` AND e.`salary` <= j.`highest_sal`;
|
|
|
|
+
|
|
|
|
+#7.2、自连接 vs 非自连接
|
|
|
|
+
|
|
|
|
+#自连接的例子:
|
|
|
|
+#练习:查询员工id,员工姓名及其管理者的id和姓名
|
|
|
|
+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`;
|
|
|
|
+
|
|
|
|
+#7.3、内连接 vs 外连接
|
|
|
|
+
|
|
|
|
+#内连接:合并具有同一列的两个以上的表的行,结果集中不包含一个表与另一个表不匹配的行
|
|
|
|
+SELECT employee_id,department_name
|
|
|
|
+FROM employees e,departments d
|
|
|
|
+WHERE e.`department_id` = d.`department_id`; #只有106条记录
|
|
|
|
+
|
|
|
|
+#外连接:合并具有同一列的两个以上的表的行,结果集中除了包含一个表与另一个表匹配的行之外,还查询到了左表或右表中不匹配的行
|
|
|
|
+
|
|
|
|
+#外连接的分类:左外连接、右外连接、满外连接
|
|
|
|
+
|
|
|
|
+#左外连接:两个表在连接过程中除了返回满足连接条件的行以外,还返回左表中不满足条件的行,这种连接称为左外连接。
|
|
|
|
+#右外连接:两个表在连接过程中除了返回满足连接条件的行以外,还返回右表中不满足条件的行,这种连接称为右外连接。
|
|
|
|
+
|
|
|
|
+#练习:查询所有的员工的last_name,department_name信息
|
|
|
|
+#题目中包含了“所有的”,所以就可能存在不匹配的数据,因此一定是外连接
|
|
|
|
+SELECT employee_id,department_name
|
|
|
|
+FROM employees e,departments d
|
|
|
|
+WHERE e.`department_id` = d.department_id; #需要使用左外连接
|
|
|
|
+
|
|
|
|
+#SQL92语法实现内连接:(上面的写法就是)
|
|
|
|
+#SQL92语法实现外连接:使用+ -----MySQL不支持SQL92语法中外连接的写法!(Oracle支持)
|
|
|
|
+#不支持
|
|
|
|
+SELECT employee_id,department_name
|
|
|
|
+FROM employees e,departments d
|
|
|
|
+WHERE e.`department_id` = d.department_id(+);
|
|
|
|
+
|
|
|
|
+#SQL99语法中使用JOIN ...ON的方式实现多表的查询。这种方式也能解决外连接的问题。
|
|
|
|
+#MySQL是支持此种方式的。
|
|
|
|
+
|
|
|
|
+#SQL99语法如何实现多表的查询。
|
|
|
|
+
|
|
|
|
+#SQL99语法实现内连接:(INNER可以省略)
|
|
|
|
+SELECT last_name,department_name
|
|
|
|
+#FROM employees e INNER JOIN departments d
|
|
|
|
+FROM employees e JOIN departments d
|
|
|
|
+ON e.department_id = d.department_id;
|
|
|
|
+
|
|
|
|
+SELECT last_name,department_name,city
|
|
|
|
+FROM employees e JOIN departments d
|
|
|
|
+ON e.department_id = d.department_id
|
|
|
|
+JOIN locations l
|
|
|
|
+ON d.location_id = l.location_id;
|
|
|
|
+
|
|
|
|
+#练习:查询所有的员工的last_name,department_name信息
|
|
|
|
+#左外连接:(因为加了LEFT,所以OUTER也可以省略)
|
|
|
|
+SELECT last_name,department_name
|
|
|
|
+#FROM employees e LEFT OUTER JOIN departments d
|
|
|
|
+FROM employees e LEFT JOIN departments d
|
|
|
|
+ON e.department_id = d.department_id;
|
|
|
|
+
|
|
|
|
+#右外连接:(因为加了RIGHT,所以OUTER也可以省略)
|
|
|
|
+SELECT last_name,department_name
|
|
|
|
+#FROM employees e RIGHT OUTER JOIN departments d
|
|
|
|
+FROM employees e RIGHT JOIN departments d
|
|
|
|
+ON e.department_id = d.department_id;
|
|
|
|
+
|
|
|
|
+#满外连接:MySQL不支持FULL OUTER JOIN的方式(Oracle支持)
|
|
|
|
+SELECT last_name,department_name
|
|
|
|
+FROM employees e FULL OUTER JOIN departments d
|
|
|
|
+ON e.department_id = d.department_id;
|
|
|
|
+
|
|
|
|
+#8、UNION和UNION ALL的使用
|
|
|
|
+#UNION:会执行去重的操作
|
|
|
|
+#UNION ALL:不会执行去重的操作
|
|
|
|
+#结论:如果明确知道合并数据后的结果数据不存在重复数据,或者不需要去除重复的
|
|
|
|
+#数据,则尽量使用UNION ALL语句,以提高数据查询的效率。
|
|
|
|
+
|
|
|
|
+#9、7种JOIN的实现
|
|
|
|
+
|
|
|
|
+#中图:内连接
|
|
|
|
+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;
|
|
|
|
+
|
|
|
|
+#左下图:满外连接
|
|
|
|
+#方式1:左上图 UNION ALL 右中图
|
|
|
|
+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;
|
|
|
|
+
|
|
|
|
+#方式2:左中图 UNION ALL 右上图
|
|
|
|
+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;
|
|
|
|
+
|
|
|
|
+#右下图:左中图 UNION ALL 右中图
|
|
|
|
+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;
|
|
|
|
+
|
|
|
|
+#10、SQL99语法的新特性1:自然连接
|
|
|
|
+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;
|
|
|
|
+
|
|
|
|
+#NATURAL JOIN:它会帮你自动查询两张连接表中“所有相同的字段”,然后进行“等值连接”
|
|
|
|
+SELECT employee_id,last_name,department_name
|
|
|
|
+FROM employees e NATURAL JOIN departments d;
|
|
|
|
+
|
|
|
|
+#11、SQL99语法的新特性2:USING
|
|
|
|
+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);
|
|
|
|
+
|
|
|
|
+#拓展
|
|
|
|
+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;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|