MySQL连接查询(多表连接查询:内连接,外连接,交叉连接详解)
6:多表连接查询
笛卡尔乘积:如果连接条件省略或无效则会出现
解决办法:添加上连接条件
连接查询的分类:
1.按年代分类:
1)sql 92标准:仅仅支持内连接
2)sql 99标准 **(推荐使用)** :支持内连接、外连接(左外 和 右外)、交叉连接
2.按功能分类:
1)内连接:
等值连接
非等值连接
自连接
2)外连接:
左外连接
右外连接
全外连接
3)交叉连接
一、传统模式下的连接 :等值连接——非等值连接
1.等值连接的结果 = 多个表的交集
2.n表连接,至少需要n-1个连接条件
3.多个表不分主次,没有顺序要求
4.一般为表起别名,提高阅读性和性能
二、sql99语法:通过join关键字实现连接
含义:1999年推出的sql语法
支持:
等值连接、非等值连接 (内连接)
外连接
交叉连接
语法:
select 字段,…
from 表1
【inner|left outer|right outer|cross】join 表2 on 连接条件
【inner|left outer|right outer|cross】join 表3 on 连接条件
【where 筛选条件】
【group by 分组字段】
【having 分组后的筛选条件】
【order by 排序的字段或表达式】
好处:语句上,连接条件和筛选条件实现了分离,简洁明了!
三、自连接
案例:查询员工名和直接上级的名称
sql99
SELECT e.last_name,m.last_name
FROM employees e
JOIN employees m ON e.`manager_id`=m.`employee_id`;
sql92
SELECT e.last_name,m.last_name
FROM employees e,employees m
WHERE e.`manager_id`=m.`employee_id`;
一、等值连接
1)多表等值连接的结果实际上为多个表的交集部分
2)n张表进行连接,则至少需要 n-1 个连接条件
3)多表的顺序没有要求
4) 一般需要为表起别名,因为可能同一个字段名,会在多张查询的表中存在。即可以为表取别名,区分多个重名的字段。为表使用别名后,只能使用别名去"select"!
5) 等值连接可以搭配排序(order by)、分组(group by)、筛选(where/and/like)来使用
# sql 92
# 可以实现三表连接
# 查询员工名、部门名、和所在的城市
SELECT 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 city LIKE 's%'
ORDER BY department_name DESC;
# 加分组条件
# 查询每个城市的部门个数
SELECT COUNT(*) 个数 , city
FROM departments d , locations l
WHERE d.location_id = l.location_id
GROUP BY city;
# sql 99
# 1.等值连接
# 查询员工名、部门名
SELECT last_name,department_name
FROM employees e
INNER JOIN departments d
ON e.department_id = d.department_id;
# 查询名字中包含e的员工名和工种名
SELECT last_name , job_title,j.job_id
FROM employees e
INNER JOIN jobs j
on e.job_id = j.job_id
WHERE e.last_name LIKE '%e%';
# 查询部门个数>3的城市名和部门个数,(添加分组+筛选)
SELECT city,COUNT(*) 部门个数
FROM locations l
INNER JOIN departments d
ON l.location_id = d.location_id
GROUP BY city
HAVING 部门个数>3;
# 查询部分的员工个数>3的部门名和员工个数,并按员工个数降序排序
SELECT COUNT(*) 个数,department_name
FROM departments d
INNER JOIN employees e
ON e.department_id = d.department_id
GROUP BY department_name
HAVING COUNT(*) > 3
ORDER BY COUNT(*) DESC;
# 查询员工名、部门名、工种名,并按部门名降序排列(三表连接)
SELECT last_name,department_name,job_title
FROM employees e
INNER JOIN jobs j ON e.job_id = j.job_id
INNER JOIN departments d ON e.department_id = d.department_id
ORDER BY department_name DESC;
sql 99 特点:
1、也可添加排序、分组、筛选
2、inner 可以省略
3、 筛选条件放在where后面,连接条件放在on后面,提高分离性,便于阅读
4、inner join连接 和sql92语法中的等值连接效果相同,都是查询多表的交集
二、非等值连接
表与表之间没有相同项(或有相同但是不能用),但是表之间某个或某些项直接存在着一定的关系。
比如说员工信息表,里面包含员工工资,另外一张工资等级表将工资进行等级划分,而员工的工资就可以根据工资等级表来划分为某个等级。
where 列名 BETWEEN … AND …
# sql 92
# 非等值连接
# 查询员工的工资和工资级别
SELECT salary , grade_level
FROM employees e, job_grades g
WHERE salary BETWEEN g.lowest_sal AND highest_sal
ORDER BY g.grade_level;
# AND g.grade_level = 'A';
# sql 99
# 非等值连接
# 查询员工的工资级别
SELECT salary , grade_level
FROM employees e
INNER JOIN job_grades g
ON e.salary BETWEEN g.lowest_sal AND g.highest_sal;
# 查询每个工资级别的员工个数>20的个数,并按工资级别降序排列
SELECT salary , grade_level , COUNT(*)
FROM employees e
INNER JOIN job_grades g
ON e.salary BETWEEN g.lowest_sal AND g.highest_sal
GROUP BY grade_level
HAVING count(*) > 20
ORDER BY grade_level DESC;
三、自连接 :自己连接自己
自连接相当于等值连接,不同的是等值连接的项在不同的表单当中,而自连接的连接项在同一个表单中。单一表单中某项和另外一项存在着关联关系。
比如说员工信息表中,普通员工A的领导是B,而B本身也是员工,因此也包含着员工信息表中。所以A的manager_id就是B的employee_id
# sql 92
# 自连接
# 查询员工名 和 上级的名称
SELECT e.employee_id , e.last_name , m.employee_id , m.last_name
FROM employees e ,employees m
WHERE e.manager_id = m.employee_id;
# sql 99
# 自连接
# 查询员工的名字、上级的名字
SELECT e.last_name , m.last_name
FROM employees e
INNER JOIN employees m
ON e.employee_id = m.manager_id;
# 查询包含字符k的员工名字、上级的名字
SELECT e.last_name , m.last_name
FROM employees e
INNER JOIN employees m
ON e.employee_id = m.manager_id
WHERE e.last_name LIKE '%k%';
二、外连接
应用场景:用于查询一个表中有,但是另一个表中没有的记录。
特点:
1)外连接的查询结果为主表中的所有记录。如果从表中有和它匹配的(也就是连接条件成立),则显示匹配的值。如果从表中没有和它匹配的,则显示null。
外连接查询的结果 = 内连接查询的结果 + 主表中有而从表中没有的记录
2)左外连接,left join 左边的是主表
右外连接,right join 右边的是主表
# sql 99
# 外连接
# 查询男朋友 不在男神表中的 女神名
USE girls;
SELECT * FROM boys;
# 左外连接
SELECT b.name , bo.*
FROM beauty b
LEFT OUTER JOIN boys bo
ON b.boyfriend_id = bo.id
WHERE bo.id IS NULL;
# 右外连接
SELECT b.name , bo.*
FROM boys bo
RIGHT OUTER JOIN beauty b
ON b.boyfriend_id = bo.id
WHERE bo.id IS NULL;
# 查询哪个部门没有员工
# 左外
USE myemployees
SELECT d.* , e.employee_id
FROM departments d
LEFT OUTER JOIN employees e
ON d.department_id = e.department_id
WHERE e.employee_id IS NULL;
# 右外
SELECT d.* , e.employee_id
FROM employees e
RIGHT OUTER JOIN departments d
ON d.department_id = e.department_id
WHERE e.employee_id IS NULL;
3)左外和右外交换两个表的顺序时,可以实现同样的效果
4) 全外连接 = 内连接的结果 + 表1中有但表2中没有的结果 + 表2中有但表1中没有的结果
# 全外
use girls
SELECT b.* ,BOTH.*
FROM beauty b
FULL OUTER JOIN boys bo
ON b.boyfirend_id = bo.id;
5)交叉连接(笛卡尔积)
# 交叉连接(笛卡尔积)
USE girls
SELECT b.* ,bo.*
FROM beauty b
CROSS JOIN boys bo;
常见连接类型总结: