SELECT employees.employee_id, employees.last_name,employees.department_id, departments.department_id,departments.location_id FROM employees, departments WHERE employees.department_id = departments.department_id;
拓展1:多个连接条件与 AND 操作符
拓展2:区分重复的列名
多个表中有相同列时,必须在列名之前加上表名前缀。
在不同表中具有相同列名的列可以用表名加以区分。
拓展3:表的别名
使用别名可以简化查询。
列名前使用表名前缀可以提高查询效率。
1 2 3
SELECT e.employee_id, e.last_name, e.department_id, d.department_id, d.location_id FROM employees e , departments d WHERE e.department_id = d.department_id;
正例 :select t1.name from table_first as t1,table_second as t2 where t1.id=t2.id;
反例:在某业务中,由于多表关联查询语句没有加表的别名(或表名)的限制,正常运行两年后,最近在某个表中增加一个同名字段,在预发布环境做数据库变更后,线上查询语句出现出 1052 异常:Column 'name' in field list is ambiguous。
拓展4:连接多个表
连接 n个表,至少需要 n-1 个连接条件。比如,连接三个表,至少需要两个连接条件。
非等值连接
1 2
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;
自连接 vs 非自连接
1 2 3
SELECT CONCAT(worker.last_name ,' works for ', manager.last_name) FROM employees worker, employees manager WHERE worker.manager_id = manager.employee_id ;
#中图:内连接 A∩B SELECT employee_id,last_name,department_name FROM employees e JOIN departments d ON e.`department_id` = d.`department_id`;
1 2 3 4
#左上图:左外连接 SELECT employee_id,last_name,department_name FROM employees e LEFTJOIN departments d ON e.`department_id` = d.`department_id`;
1 2 3 4
#右上图:右外连接 SELECT employee_id,last_name,department_name FROM employees e RIGHTJOIN departments d ON e.`department_id` = d.`department_id`;
1 2 3 4 5
#左中图:A - A∩B SELECT employee_id,last_name,department_name FROM employees e LEFTJOIN departments d ON e.`department_id` = d.`department_id` WHERE d.`department_id` ISNULL
1 2 3 4 5
#右中图:B-A∩B SELECT employee_id,last_name,department_name FROM employees e RIGHTJOIN departments d ON e.`department_id` = d.`department_id` WHERE e.`department_id` ISNULL
1 2 3 4 5 6 7 8 9
#左下图:满外连接 #左中图+右上图 A∪B SELECT employee_id,last_name,department_name FROM employees e LEFTJOIN departments d ON e.`department_id` = d.`department_id` WHERE d.`department_id` ISNULL UNIONALL #没有去重操作,效率高 SELECT employee_id,last_name,department_name FROM employees e RIGHTJOIN departments d ON e.`department_id` = d.`department_id`;
1 2 3 4 5 6 7 8 9
#右下图 #左中图+右中图 A∪B-A∩B或者(A- A∩B)∪(B-A∩B) SELECT employee_id,last_name,department_name FROM employees e LEFTJOIN departments d ON e.`department_id` = d.`department_id` WHERE d.`department_id` ISNULL UNIONALL SELECT employee_id,last_name,department_nameFROM employees e RIGHTJOIN departments d ON e.`department_id` = d.`department_id` WHERE e.`department_id` ISNULL
语法格式小结
左中图
1 2 3
#实现 A-A∩B select 字段列表 from A表 leftjoin B表 on 关联条件 where 从表关联字段 isnulland 等其他子句;
右中图
1 2 3
#实现B - A∩B select 字段列表 from A表 rightjoin B表 on 关联条件 where 从表关联字段 isnulland 等其他子句;
左下图
1 2 3 4 5 6 7
#实现查询结果是A∪B #用左外的A,union 右外的B select 字段列表 from A表 leftjoin B表 on 关联条件 where 等其他子句 union select 字段列表 from A表 rightjoin B表 on 关联条件 where 等其他子句;
右下图
1 2 3 4 5 6 7
#实现 A∪B - A∩B 或 (A- A∩B)∪(B-A∩B) #使用左外的 (A - A∩B) union 右外的(B - A∩B) select 字段列表 from A表 leftjoin B表 on 关联条件 where 从表关联字段 isnulland 等其他子句 union select 字段列表 from A表 rightjoin B表 on 关联条件 where 从表关联字段 isnulland 等其他子句
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`;
在SQL99中你可以写成:
1 2
SELECT employee_id,last_name,department_name FROM employees e NATURALJOIN departments d;
USING连接
当我们进行连接的时候,SQL99还支持使用 USING 指定数据表里的同名字段进行等值连接。但是只能配合JOIN一起使用。比如:
1 2 3
SELECT employee_id,last_name,department_name FROM employees e JOIN departments d USING (department_id);
我们要控制连接表的数量。多表连接就相当于嵌套 for 循环一样,非常消耗资源,会让 SQL 查询性能下降得很严重,因此不要连接不必要的表。在许多 DBMS 中,也都会有最大连接表的限制。
练习
显示所有员工的姓名,部门号和部门名称。
1 2 3
SELECT e.last_name,e.department_id,d.department_name FROM employees e LEFTJOIN departments d ON e.department_id = d.department_id;
查询90号部门员工的job_id和90号部门的location_id
1 2 3 4
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;
选择所有有奖金的员工的 last_name , department_name , location_id , city
1 2 3 4 5
SELECT e.last_name,d.department_name,d.location_id,l.city FROM employees e LEFTJOIN departments d ON e.department_id = d.department_id LEFTJOIN locations l ON d.location_id = l.location_id WHERE e.commission_pct ISNOTNULL;
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 d.department_name,l.street_address,e.last_name,j.job_title,e.salary FROM employees e JOIN departments d ON e.department_id = d.department_id JOIN locations l ON d.location_id = l.location_id JOIN jobs j ON e.job_id = j.job_id WHERE d.department_name ='Executive';
选择指定员工的姓名,员工号,以及他的管理者的姓名和员工号,结果类似于下面的格式
1 2 3
employees Emp# manager Mgr#
kochhar 101 king 100
查询哪些部门没有员工
1 2 3 4
SELECT d.department_id FROM departments d LEFTJOIN employees e ON d.department_id = e.department_id WHERE e.department_id ISNULL;
查询哪个城市没有部门
1 2 3 4
SELECT l.location_id,l.city FROM locations l LEFTJOIN departments d ON l.location_id = d.location_id WHERE d.location_id ISNULL;
查询部门名为 Sales 或 IT 的员工信息
1 2 3 4
SELECT e.employee_id,e.last_name,e.department_id,d.department_name FROM employees e JOIN departments d ON e.department_id = d.department_id WHERE d.department_name ='Sales'OR d.department_name ='IT';