MYSQL 多表联查详解

目录

一、一个案例引发的多表连接

二、笛卡尔积的错误和与正确的多表查询

2.1、笛卡尔积错误展示

2.2、笛卡尔积解决方法

2.3、练习

三、多表查询分类

3.1、等值连接 vs 非等值连接

3.2、自连接 vs 非自连接

3.3、内连接 vs 外连接

内连接(inner join)

外连接

左外连接(left join)

右外连接(right join)

3.4、七种JOINS查询

左2图

右2图

左下图

右下图

3.5、自然连接(natural join)

3.6、using用法


一、一个案例引发的多表连接

先看这三张表的结构:

MYSQL 多表联查详解_第1张图片

员工表的department_id关联部门表的主键department_id,而部门表的location_id关联地区表的主键location_id。

意思就是员工所属部门,而部门所属地区,从而可以查出员工所属地区在哪。

二、笛卡尔积的错误和与正确的多表查询

2.1、笛卡尔积错误展示

案例:查询员工的姓名及其部门名称

SELECT last_name, department_name FROM employees, departments;

MYSQL 多表联查详解_第2张图片

结果怎么查出这么多条记录?

我员工表只有107条记录,而部门表更少,只有27条记录,那2889条记录是怎么来的呢?

学过数学的小伙伴们估计已经猜到了答案,是107 * 27 = 2889。是每个员工都与每个部门匹配的一遍,这就是笛卡尔积。

2.2、笛卡尔积解决方法

SQL92中,笛卡尔积也称为交叉连接 ,英文是 CROSS JOIN 。在 SQL99 中也是使用 CROSS JOIN表示交叉连接。它的作用就是可以把任意表进行连接,即使这两张表不相关。

说白了,其实就是没有写连接条件,修改如下:

SELECT last_name, department_name FROM employees, departments where employees.department_id = departments.department_id;

MYSQL 多表联查详解_第3张图片

2.3、练习

问题:查出员工所在的部门和地区,要求显示出员工名、部门名、地区名

SELECT
	last_name,
	department_name,
	city
FROM
	employees,
	departments,
	locations
WHERE
	employees.department_id = departments.department_id
AND departments.location_id = locations.location_id;

从SQL语句看出,需要三张表关联查询,条件先是员工表的department_id关联部门表的department_id,然后部门表的location_id再关联地区表的location_id。

MYSQL 多表联查详解_第4张图片

三、多表查询分类

3.1、等值连接 vs 非等值连接

顾名思义,之前我们where条件都是谁等于谁,非等值连接就是不等于谁。

例如:我们先看员工表和工作等级表结构

MYSQL 多表联查详解_第5张图片

MYSQL 多表联查详解_第6张图片

现在想查出每个员工的薪资等级。

SELECT
	e.last_name,
	e.salary,
	j.grade_level
FROM
	employees e,
	job_grades j
WHERE
	e.salary >= j.lowest_sal
AND e.salary <= j.highest_sal

MYSQL 多表联查详解_第7张图片

这就叫非等值连接。

3.2、自连接 vs 非自连接

先看看员工表的manager_id(管理者ID)。

MYSQL 多表联查详解_第8张图片

问题:查询员工id,员工姓名及其管理者的id和姓名

注意:管理者id要和employee_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

MYSQL 多表联查详解_第9张图片

顾名思义,自己和自己连接,叫做自连接。

3.3、内连接 vs 外连接

内连接(inner join)

是将两个或多个表中满足指定条件的行连接在一起,形成一个新的结果集的操作。

如:

SELECT
	e.last_name,
	dept.department_name
FROM
	employees e
INNER JOIN departments dept ON e.department_id = dept.department_id

外连接

左外连接(left join)

左表数据全部查出,右表只返回符合条件的数据。

例如:查询全部的员工和所在部门

MYSQL 多表联查详解_第10张图片

员工表共有107条数据,其中有位员工是没有部门的,如果是内连接,最后返回的是106条数据,不包括没有部门的那位员工,但我现在的需求是包含这位员工,这就用到我们的左外连接。

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

MYSQL 多表联查详解_第11张图片

右外连接(right join)

右表数据全部查出,左表只返回符合条件的数据。

例如:查询全部的部门和部门下的员工

SELECT
	e.last_name,
	dept.department_name
FROM
	employees e
RIGHT JOIN departments dept ON e.department_id = dept.department_id;

MYSQL 多表联查详解_第12张图片

右表中有的部门下并没有员工,有的部门下有很多员工。

其实可以这样想,因为我是右外连接,我以右表为主,拿每一个部门都去和左表所有记录进行比对,符合条件的就记录下来,不符合的把右表记录下来,其实就相当于Java里的双层for循环。

for (int i = 0, i < dept.size(), i++) {  // 遍历部门表
    for (int j = 0, i < emp.size(), j++) {  //遍历员工表
        // 拿部门表的部门id和员工表的部门id比对
        if (dept.getDepartmentId().equals(emp.getDepartmentId())) {
            
        }
    }
}

3.4、七种JOINS查询

MYSQL 多表联查详解_第13张图片

左1:左外连接(left join)

右1:右外连接(right join)

中间:内连接(inner join)

左2图

例:

SELECT
	e.last_name,
	dept.department_name
FROM
	employees e
LEFT JOIN departments dept ON e.department_id = dept.department_id
WHERE
	dept.department_id IS NULL;

MYSQL 多表联查详解_第14张图片

如图所示,如果sql不加where条件,单纯的左外连接,那查出的是左表全部数据,当然也包括没有部门的那位员工,符合左1图,但现在加了where dept.department_id IS NULL条件,我就把没有部门的那位员工给单独取出来了,注意左2图红色部分是不满足on后面的条件的那部分。

右2图

SELECT
	e.last_name,
	dept.department_name
FROM
	employees e
RIGHT JOIN departments dept ON e.department_id = dept.department_id
WHERE
	e.department_id IS NULL;

MYSQL 多表联查详解_第15张图片

左下图

属于满外连接,你可以像拼图一样,将左1图和右2图用union拼在一起。

SELECT
	last_name,
	department_name
FROM
	employees e
LEFT JOIN departments dept ON e.department_id = dept.department_id
UNION ALL
SELECT
	last_name,
	department_name
FROM
	employees e
RIGHT JOIN departments dept ON e.department_id = dept.department_id
WHERE
	e.department_id IS NULL;

MYSQL 多表联查详解_第16张图片

右下图

也可以用拼图的方式,将左2和右2使用union all连接起来。

3.5、自然连接(natural join)

它会帮你自动查询两张连接表中所有相同的字段,然后进行等值连接。

比如我们看员工表和部门表

MYSQL 多表联查详解_第17张图片

有两个相同的条件。那么如下是自然连接的写法,等于普通连接的写法。

# 自然连接
SELECT
	employee_id,
	last_name,
	department_name
FROM
	employees e
NATURAL JOIN departments d;


# 普通连接
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;

3.6、using用法

using用来简写on的条件。

如下:

# 内连接 on后写条件
SELECT
	e.last_name,
	dept.department_name
FROM
	employees e
INNER JOIN departments dept ON e.department_id = dept.department_id;


# 内连接 using写条件
SELECT
	e.last_name,
	dept.department_name
FROM
	employees e
INNER JOIN departments dept using(department_id);

注意:on条件后,只有当左表的字段名和右表字段名一致的时候才能使用using,你像on e.dpetId = d.department_id就不能用using。

你可能感兴趣的:(#,MYSQL,mysql,数据库,多表查询,左连接,内连接,笛卡尔积,left,join)