MySQL的多表查询

一、多表查询的分类

1、等值连接和非等值连接

(1)等值连接——使用等号进行连接

举例:

# 查询员工的employee_id,last_name,department_name和department_id
# 多个表中有相同列时,必须在列名之前加上表名前缀,同时使用表的别名可以简化查询和提高查询效率
# 如果我们使用了表的别名,在查询字段中、过滤条件中就只能使用别名进行代替,不能使用原有的表名,否则就会报错。
SELECT e.employee_id, e.last_name,d.department_id, d.location_id 
FROM employees e , departments d 
WHERE e.department_id = d.department_id;


# 查询员工的employee_id,last_name,department_name,city
# 如果有n个表实现多表的查询,则需要至少n-1个连接条件
SELECT e.employee_id,e.last_name,department_name,city
FROM employees e,departments d,locations l
WHERE e.department_id=d.department_id AND d.location_id=l.location_id;# 多个连接条件与 AND 操作符

MySQL的多表查询_第1张图片
(2)非等值连接——除了使用等号之外的符号进行连接,包括比较运算符(<,<=,>,>=, BETWEEN)和谓词运算(LIKE, IN, NOT 等)在内的所有的逻辑运算

举例:

# 查询所有员工的last_name,salary和grade_level

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;

MySQL的多表查询_第2张图片

2、自连接和非自连接

(1)自连接——使用自己的表连接自己的表

举例:

# 查询员工id,员工姓名及其管理者的id和姓名
SELECT e.employee_id,e.last_name,m.manager_id,m.last_name
FROM employees e,employees m # 将同一个员工表看成两份,因为员工表中既包含普通员工信息又包含管理者信息
WHERE e.manager_id=m.employee_id

MySQL的多表查询_第3张图片

(2)非自连接——使用了多张不同的表(1中的等值连接和非等值连接都是非自连接)

3、内连接和外连接

(1)内连接——合并具有同一列的两个以上的表的行, 结果集中不包含一个表与另一个表不匹配的行

(2)外连接——两个表在连接过程中除了返回满足连接条件的行以外还返回左(或右)表中不满足条件的行 ,这种连接称为左(或右) 外连接。没有匹配的行时, 结果表中相应的列为空(NULL)。如果是左外连接,则连接条件中左边的表也称为 主表 ,右边的表称为 从表 ;如果是右外连接,则连接条件中右边的表也称为 主表 ,左边的表称为 从表

注意:在 SQL92 中采用(+)代表从表所在的位置。即左或右外连接中,(+) 表示哪个是从表。在 SQL92 中,只有左外连接和右外连接,没有满(或全)外连接。我们在现实开发场景中一般使用SQL99语法即JOIN…ON…子句实现多表查询

二、SQL99语法实现多表查询

(1)基本语法

# 可以使用 ON 子句指定额外的连接条件,此连接条件可以与其他条件分开
# ON子句使语句具有更高的易读性
# 关键字 JOIN、INNER JOIN、CROSS JOIN 的含义是一样的,都表示内连接
SELECT table1.column, table2.column,table3.column 
FROM table1 
 JOIN table2 ON table1 和 table2 的连接条件
 JOIN table3 ON table2 和 table3 的连接条件

(2)内连接(INNER JOIN)的实现

语法:

SELECT 字段列表 
FROM A表 INNER JOIN B表 
ON 关联条件 
WHERE 等其他子句;

举例:

# 查询员工的employee_id,last_name,department_id,department_name和所在部门的location_id
# 关键字 JOIN、INNER JOIN、CROSS JOIN 的含义是一样的,都表示内连接

# 方式一
SELECT e.employee_id,e.last_name,e.department_id,
       d.department_id,d.location_id
FROM employees e JOIN departments d
ON e.department_id=d.department_id;

# 方式二
SELECT e.employee_id,e.last_name,e.department_id,
       d.department_id,d.location_id
FROM employees e INNER JOIN departments d
ON e.department_id=d.department_id;

# 方式三
SELECT e.employee_id,e.last_name,e.department_id,
       d.department_id,d.location_id
FROM employees e CROSS JOIN departments d
ON e.department_id=d.department_id;

# 方式四(SQL92语法实现内连接)
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;

# 查询员工的employee_id,department_name和部门所在的城市city
SELECT employee_id,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;
     

MySQL的多表查询_第4张图片
(3)外连接(OUTER JOIN)的实现(看见题目中的“所有”二字要敏感,可能使用外连接,且左外或右外连接中的左右只是逻辑上的左右。调换顺序,左外连接可以变成右外连接,右外连接可以变成左外连接)

I、左外连接

语法:

#实现查询结果是A 
SELECT 字段列表 
#FROM A表 LEFT OUTER JOIN B表 (OUTER可以省略不写)
FROM A表 LEFT JOIN B表 
ON 关联条件 
WHERE 等其他子句;

举例:

# 查询所有员工的last_name,department_id和department_name
# 方式一
SELECT e.last_name,e.department_id,d.department_name
FROM employees e
LEFT JOIN departments d ON e.department_id=d.department_id;

# 方式二
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;

MySQL的多表查询_第5张图片
II、右外连接

语法:

#实现查询结果是B 
SELECT 字段列表 
# FROM A表 RIGHT OUTER JOIN B表 (OUTER可以省略不写)
FROM A表 RIGHT JOIN B表 
ON 关联条件 
WHERE 等其他子句;

举例:

# 查询所有员工的last_name,department_id和department_name
# 方式一
SELECT e.last_name,e.department_id,d.department_name
FROM employees e
RIGHT JOIN departments d ON e.department_id=d.department_id;

# 方式二
SELECT e.last_name,e.department_id,d.department_name
FROM employees e
RIGHT OUTER JOIN departments d ON e.department_id=d.department_id;

MySQL的多表查询_第6张图片

III、满外连接

1、满外连接的结果 = 左右表匹配的数据 + 左表没有匹配到的数据 + 右表没有匹配到的数据。
2、SQL99是支持满外连接的。使用FULL JOIN 或 FULL OUTER JOIN来实现。
3、MySQL不支持FULL JOIN,但是可以用 LEFT JOIN UNION RIGHT join代替。
MySQL的多表查询_第7张图片
IV、左外连接和右外连接的区别
MySQL的多表查询_第8张图片

三、UNION的使用

(1)利用UNION关键字,可以给出多条SELECT语句,并将它们的结果组合成单个结果集。合并
时,两个表对应的列数和数据类型必须相同,并且相互对应。各个SELECT语句之间使用UNION或UNION ALL关键字分隔。

语法:

SELECT column,... FROM tableA
UNION [ALL] 
SELECT column,... FROM tableB

(2)UNION操作符——返回两个查询的结果集的并集,去除重复记录
MySQL的多表查询_第9张图片

(3)UNION ALL操作符——返回两个查询的结果集的并集。对于两个结果集的重复部分,不去重
MySQL的多表查询_第10张图片
注意:

执行UNION ALL语句时所需要的资源比UNION语句少。如果明确知道合并数据后的结果数据
不存在重复数据,或者不需要去除重复的数据,则尽量使用UNION ALL语句,以提高数据查询的效 率。

举例:

# 查询部门编号>90或邮箱包含a的员工信息
# 方式一
SELECT *
FROM employees
WHERE email LIKE '%a%' OR department_id>90;

# 方式二
SELECT * FROM employees WHERE email LIKE '%a%'
UNION
SELECT * FROM employees WHERE department_id>90;

MySQL的多表查询_第11张图片
四、七种SQL JOINS 的实现

MySQL的多表查询_第12张图片

#中图:内连接 A∩B 
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 LEFT JOIN departments d ON e.department_id = d.department_id;

#右上图:右外连接 
SELECT employee_id,last_name,department_name 
FROM employees e RIGHT JOIN departments d ON e.department_id= d.department_id;

#左中图:A - A∩B 
SELECT employee_id,last_name,department_name 
FROM employees e LEFT JOIN departments d ON e.department_id = d.department_id 
WHERE d.department_id IS NULL;

#右中图:B-A∩B 
SELECT employee_id,last_name,department_name 
FROM employees e RIGHT JOIN departments d ON e.department_id = d.department_id
WHERE e.department_id IS NULL;

#左下图:满外连接 
# 左中图 + 右上图 A∪B 
SELECT employee_id,last_name,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,last_name,department_name 
FROM employees e RIGHT JOIN departments d ON e.department_id = d.department_id;

#右下图 
#左中图 + 右中图 A ∪B- A∩B 或者 (A - A∩B) ∪ (B - A∩B) 
SELECT employee_id,last_name,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,last_name,department_name FROM employees e RIGHT JOIN departments d ON e.department_id = d.department_id
WHERE e.department_id IS NULL

MySQL的多表查询_第13张图片
五、SQL99新特性

(1)自然连接

SQL99 在 SQL92 的基础上提供了一些特殊语法,比如 NATURAL JOIN 用来表示自然连接。我们可以把自然连接理解为 SQL92 中的等值连接。它会帮你自动查询两张连接表中 所有相同的字段 ,然后进行等值连接 。

举例:

# 以下两种查询方式都一样,实际开发中使用等值连接即可即使用方式一
# 因为自然连接默认把所有相同字段连接相当于增加了约束条件,使查询出来的数据更少
# 方式一
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;

MySQL的多表查询_第14张图片
(2)USING

当我们进行连接的时候,SQL99还支持使用 USING 指定数据表里的同名字段进行等值连接(不适用于自连接)。但是只能配合JOIN一起使用。与自然连接 NATURAL JOIN 不同的是,USING 指定了具体的相同的字段名称,你需要在 USING的括号 () 中填入要指定的同名字段。同时使用 JOIN…USING 可以简化 JOIN ON 的等值连接。

举例:

# 以下两种查询方式都一样
# 方式一
SELECT employee_id,last_name,department_name 
FROM employees e ,departments d 
WHERE e.department_id = d.department_id;

# 方式二
SELECT employee_id,last_name,department_name 
FROM employees e JOIN departments d 
USING (department_id);

MySQL的多表查询_第15张图片
六、总结

(1)表连接的约束条件可以有三种方式:WHERE(SQL92语法), ON(SQL99语法), USING(SQL99语法)。

WHERE:适用于所有关联查询。
ON :只能和JOIN一起使用,只能写关联条件。虽然关联条件可以并到WHERE中和其他条件一起写,但分开写可读性更好。
USING:只能和JOIN一起使用,而且要求两个关联字段在关联表中名称一致,而且只能表示关联字 段值相等。(条件苛刻)

(2)我们要控制连接表的数量 。多表连接就相当于嵌套 for 循环一样,非常消耗资源,会让 SQL 查询性能下
降得很严重,因此不要连接不必要的表。在许多 DBMS 中,也都会有最大连接表的限制。

七、小练习

# 1.显示所有员工的姓名,部门号和部门名称。 

SELECT e.last_name,e.department_id,d.department_name
FROM employees e LEFT JOIN departments d
ON e.department_id=d.department_id;

# 2.查询90号部门员工的job_id和90号部门的location_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;

# 3.选择所有有奖金的员工的 last_name , department_name , location_id , city 

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; 

# 4.选择city在Toronto工作的员工的 last_name , job_id , department_id , department_name 

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'

# 5.查询员工所在的部门名称、部门地址、姓名、工作号、工资,其中员工所在部门的部门名称为’Executive’ 

SELECT d.department_name,l.street_address,e.last_name,e.job_id,e.salary
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 d.department_name='Executive';


# 6.选择指定员工的姓名,员工号,以及他的管理者的姓名和员工号,结果类似于下面的格式 
# employees    Emp#        manager     
# kochhar      101         king       100 

# 想象成两个集合自连接,一个员工表和一个管理者表,员工表的管理者号等于管理者表的员工号
SELECT e.last_name "employees ",e.employee_id "Emp#",m.last_name " manager",m.employee_id "Mgr#"
FROM employees e LEFT JOIN employees m
ON e.manager_id=m.employee_id;

# 7.查询哪些部门没有员工 (想象成两个集合:部门表和员工表)

SELECT d.department_id
FROM departments d LEFT JOIN employees e
ON d.department_id=e.department_id
WHERE e.employee_id IS NULL;

# 8. 查询哪个城市没有部门 (想象成两个集合:位置表和部门表)

SELECT l.location_id
FROM locations l LEFT JOIN departments d
ON l.location_id=d.location_id
WHERE d.department_id IS NULL;

# 9. 查询部门名为 Sales 或 IT 的员工信息

SELECT *
FROM employees e JOIN departments d
ON e.department_id=d.department_id
#WHERE d.department_name='Sales' OR d.department_name='IT';
WHERE d.department_name IN ('Sales','IT');

所用数据库请看文章末尾:SQL语言和基本的select语句

你可能感兴趣的:(MySQL,MySQL,SQL,多表查询)