MYSQL学习笔记(四):多表关系、多表查询(交叉连接、内连接、外连接、自连接)、七种JSONS、集合

前言

  • 学习和使用数据库可以说是程序员必须具备能力,这里将更新关于MYSQL的使用讲解,大概应该会更新30篇+,涵盖入门、进阶、高级(一些原理分析);
  • 这一篇是内容比较多,涵盖:多表关系、多表查询(交叉连接、内连接、外连接、自连接)、七种JSONS、集合基础讲解
  • 虽然MYSQL命令很多,但是自己去多敲一点,到后面忘记了,查一下就可以回忆起来使用了;
  • 这一系列也是本人学习MYSQL做的笔记,也是为了方便后面忘记查询;
  • 参考资料:尚硅谷、黑马、csdn和知乎博客;
  • 欢迎收藏 + 关注,本人将会持续更新。

文章目录

课程使用数据文件: 后台私信获取。

多表关系

项目开发中,在进行数据库表结构设计时,会根据业务需求及业务模块之间的关系,分析并设计表结构,由于业务之间相互关联,所以各个表结构之间也存在着各种联系,基本上分为三种:

  • 一对多(多对一)
  • 多对多
  • 一对一

以上关系就是E-R图中的'1' 和 'n' / '*'含义

一对多(多对一)

案例:部门与员工的关系

关系:一个部门对应多个员工,一个员工对应一个部门

实现:在多的一方建立外键,关联另一方的主键

多对多

案例:学生与课程的关系

关系:一个学生可以选修多门课程,一门课程也可以供多个学生选择

实现:建立第三张中间表,中间表至少包含两个外键,分别关联两方主键

一对一

案例:用户与用户详细的关系

关系:一对一关系,多用于单表拆分,将一张表的基础字段放在一张表中,其他详情字段放在另一张表中,以提升操作效率。

实现:在任意一方加入一个外键,关联另一方的主键,并且设置外键为唯一约束

多表查询

  • 前面我们使用的查询,只是对单表进行查询,在具体的应用中,经常需要实现在一个查询语句中显示多张数据表的数据,这就是所谓的多表查询
  • 前提条件 :发生在两个及两个以上的表之间,表与表之间有关系(一对多、多对多、一对一),且他们之间一定的关联字段
  • 实现:首先将两个或两个以上的表按照某个条件连接起来,然后再查询到所要求的数据记录。
  • 优点:方便信息管理,提高查询效率。

😍 连接查询方式:分为交叉连接内连接外连接 查询三种,在介绍这些查询方式之前我们首先来介绍一下笛卡尔积

笛卡尔积概念:描述两个集合X和Y的所有组合,如图所示:


上面是数学概念,结合MYSQL实践如下.

在mysql中多表一起查询的时候,这个时候遵循笛卡尔积,如下案例:

mysql 复制代码
# 员工表
mysql> select * from emp;
+-------+--------+-----------+------+------------+------+------+--------+
| empno | ename  | job       | mgr  | hiredate   | sal  | comm | deptno |
+-------+--------+-----------+------+------------+------+------+--------+
|  7369 | SMITH  | CLERK     | 7902 | 1980-12-17 |  800 | NULL |     20 |
|  7499 | ALLEN  | SALESMAN  | 7698 | 1981-02-20 | 1600 |  300 |     30 |
|  7521 | WARD   | SALESMAN  | 7698 | 1981-02-22 | 1250 |  500 |     30 |
|  7566 | JONES  | MANAGER   | 7839 | 1981-04-02 | 2975 | NULL |     20 |
|  7654 | MARTIN | SALESMAN  | 7698 | 1981-09-28 | 1250 | 1400 |     30 |
|  7698 | BLAKE  | MANAGER   | 7839 | 1981-05-01 | 2850 | NULL |     30 |
|  7782 | CLARK  | MANAGER   | 7839 | 1981-06-09 | 2450 | NULL |     10 |
|  7788 | SCOTT  | ANALYST   | 7566 | 1987-04-19 | 3000 | NULL |     20 |
|  7839 | KING   | PRESIDENT | NULL | 1981-11-17 | 5000 | NULL |     10 |
|  7844 | TURNER | SALESMAN  | 7698 | 1981-09-08 | 1500 |    0 |     30 |
|  7876 | ADAMS  | CLERK     | 7788 | 1987-05-23 | 1100 | NULL |     20 |
|  7900 | JAMES  | CLERK     | 7698 | 1981-12-03 |  950 | NULL |     30 |
|  7902 | FORD   | ANALYST   | 7566 | 1981-12-03 | 3000 | NULL |     20 |
|  7934 | MILLER | CLERK     | 7782 | 1982-01-23 | 1300 | NULL |     10 |
+-------+--------+-----------+------+------------+------+------+--------+
14 rows in set (0.02 sec)

# 部门表
mysql> select * from dept;
+--------+------------+----------+
| deptno | dname      | loc      |
+--------+------------+----------+
|     10 | ACCOUNTING | NEW YORK |
|     20 | RESEARCH   | DALLAS   |
|     30 | SALES      | CHICAGO  |
|     40 | OPERATIONS | BOSTON   |
+--------+------------+----------+
4 rows in set (0.01 sec)

这个时候查询员工名字和其所对应的部门名字的时候,会发生:

mysql 复制代码
mysql> select ename, dname from emp, dept;
+--------+------------+
| ename  | dname      |
+--------+------------+
| SMITH  | OPERATIONS |
| SMITH  | SALES      |
| SMITH  | RESEARCH   |
| SMITH  | ACCOUNTING |
| ALLEN  | OPERATIONS |
| ALLEN  | SALES      |
| ALLEN  | RESEARCH   |
| ALLEN  | ACCOUNTING |
| WARD   | OPERATIONS |
| WARD   | SALES      |
| WARD   | RESEARCH   |
| WARD   | ACCOUNTING |
| JONES  | OPERATIONS |
| JONES  | SALES      |
| JONES  | RESEARCH   |
| JONES  | ACCOUNTING |
| MARTIN | OPERATIONS |
| MARTIN | SALES      |
| MARTIN | RESEARCH   |
| MARTIN | ACCOUNTING |
| BLAKE  | OPERATIONS |
| BLAKE  | SALES      |
| BLAKE  | RESEARCH   |
| BLAKE  | ACCOUNTING |
| CLARK  | OPERATIONS |
| CLARK  | SALES      |
| CLARK  | RESEARCH   |
| CLARK  | ACCOUNTING |
| SCOTT  | OPERATIONS |
| SCOTT  | SALES      |
| SCOTT  | RESEARCH   |
| SCOTT  | ACCOUNTING |
| KING   | OPERATIONS |
| KING   | SALES      |
| KING   | RESEARCH   |
| KING   | ACCOUNTING |
| TURNER | OPERATIONS |
| TURNER | SALES      |
| TURNER | RESEARCH   |
| TURNER | ACCOUNTING |
| ADAMS  | OPERATIONS |
| ADAMS  | SALES      |
| ADAMS  | RESEARCH   |
| ADAMS  | ACCOUNTING |
| JAMES  | OPERATIONS |
| JAMES  | SALES      |
| JAMES  | RESEARCH   |
| JAMES  | ACCOUNTING |
| FORD   | OPERATIONS |
| FORD   | SALES      |
| FORD   | RESEARCH   |
| FORD   | ACCOUNTING |
| MILLER | OPERATIONS |
| MILLER | SALES      |
| MILLER | RESEARCH   |
| MILLER | ACCOUNTING |
+--------+------------+
56 rows in set (0.00 sec)

查询到很多,一共 16 * 4 = 56条,这个就是笛卡尔积带来的问题,而解决这些问题,可以有如下;

交叉连接

交叉连接:返回被连接的两个表所有数据行的笛卡尔积

交叉连接不带WHERE子句,它返回被连接的两个表所有数据行的笛卡尔积

  • 查询员工及员工所在的部门信息
mysql 复制代码
SELECT * FROM emp,dept; 
SELECT * FROM emp CROSS JOIN dept; 

如果不加条件直接进行查询,则数据条数是两个表记录条数的乘积,这种结果就是我们上面介绍的 笛卡尔乘积

笛卡尔乘积公式 : A表中数据条数 * B表中数据条数 = 笛卡尔乘积

如果两张表的数据量都很大,那么这种庞大时很可怕的,想要消除笛卡尔积的无效记录,需要使用关联字段

范例:利用等值条件来处理笛卡尔积

mysql 复制代码
mysql> select ename, dname from emp e, dept d where e.deptno=d.deptno;
+--------+------------+
| ename  | dname      |
+--------+------------+
| SMITH  | RESEARCH   |
| ALLEN  | SALES      |
| WARD   | SALES      |
| JONES  | RESEARCH   |
| MARTIN | SALES      |
| BLAKE  | SALES      |
| CLARK  | ACCOUNTING |
| SCOTT  | RESEARCH   |
| KING   | ACCOUNTING |
| TURNER | SALES      |
| ADAMS  | RESEARCH   |
| JAMES  | SALES      |
| FORD   | RESEARCH   |
| MILLER | ACCOUNTING |
+--------+------------+
14 rows in set (0.00 sec)

这样一共查出来14条,比上面不加限制查出的56条少了很多

这个等值限制,就是我们接下要说的,内连接。


内连接

在表关系的笛卡尔积数据记录中,保留表关系中所有匹配的数据记录,舍弃不匹配的数据记录。按匹配的条件可以分成等值连接和不等值连接。

有两种,显式的和隐式的,返回连接表中符合连接条件和查询条件的数据行。

  • 隐式内连接
mysql 复制代码
SELECT * FROM 表1,表2 WHERE 条件;  # 本人喜欢使用
  • 显示内连接(使用关键字INNER JOIN)
mysql 复制代码
SELECT * FROM 表1 [INNER] JOIN 表2 ON 条件; 

# 上面案例用这种方式写一下,效果一样
mysql> select ename, dname from emp e inner join dept d on e.deptno=d.deptno;
+--------+------------+
| ename  | dname      |
+--------+------------+
| SMITH  | RESEARCH   |
| ALLEN  | SALES      |
| WARD   | SALES      |
| JONES  | RESEARCH   |
| MARTIN | SALES      |
| BLAKE  | SALES      |
| CLARK  | ACCOUNTING |
| SCOTT  | RESEARCH   |
| KING   | ACCOUNTING |
| TURNER | SALES      |
| ADAMS  | RESEARCH   |
| JAMES  | SALES      |
| FORD   | RESEARCH   |
| MILLER | ACCOUNTING |
+--------+------------+
14 rows in set (0.00 sec)
等值连接

在连接条件中==使用等于号(=)==运算符比较被连接列的列值,

  • 查询员工及员工部门信息
mysql 复制代码
#隐式连接
SELECT * FROM emp e,dept d WHERE e.deptno=d.deptno;
#显示连接
SELECT * FROM emp e INNER JOIN dept d ON e.deptno=d.deptno;
  • 等值连接可以使用USING来自动关联两表中相同的列
mysql 复制代码
SELECT * FROM emp INNER JOIN dept USING(deptno);
非等值连接

在连接条件使用除等于运算符以外的其它比较运算符比较被连接的 列的列值。这些运算符包括>、>=、<=、<、!>、!<和<>等。

依然分为隐式连接显示连接

  • 查询员工工资级别
mysql 复制代码
#隐式连接
SELECT * FROM emp e,salgrade s WHERE e.sal BETWEEN s.losal AND s.hisal;
#显示连接
SELECT * FROM emp e INNER JOIN salgrade s ON  e.sal BETWEEN s.losal AND s.hisal;

/*
mysql> select e.ename, s.grade from emp e inner join salgrade s on e.sal between s.losal and s.hisal;
+--------+-------+
| ename  | grade |
+--------+-------+
| SMITH  |     1 |
| ALLEN  |     3 |
| WARD   |     2 |
| JONES  |     4 |
| MARTIN |     2 |
| BLAKE  |     4 |
| CLARK  |     4 |
| SCOTT  |     4 |
| KING   |     5 |
| TURNER |     3 |
| ADAMS  |     1 |
| JAMES  |     1 |
| FORD   |     4 |
| MILLER |     2 |
+--------+-------+
14 rows in set (0.00 sec)
*/

外连接

在表关系的笛卡尔积中,不仅保留表关系中所有匹配的数据记录,而且还保留部分不匹配的记录。按照保留不匹配条件数据记录来源可以分为左外连接(LEFT OUTER JOIN)、右外连接(RIGHT OUTER JOIN)和全外连接(FULL OUTER JOIN)。

外连接使用语法如下:

mysql 复制代码
SELECT * FROM 表1 LEFT|RIGHT|FULL [OUTER] JOIN 表2 ON 条件; 
左外连接

在表关系的笛卡尔积中,出了选择相匹配的数据记录,还包含关联左边表中不匹配的数据记录。

不仅查询出匹配的数据,还查询出不匹配的数据,这个时候可以看做是以左边表为主,去匹配右边数据,在右边查找。

案例:

准备:插入一条部门编号为NULL的数据(关于插入后面会讲)

mysql 复制代码
INSERT INTO emp(empno,ename,job,mgr,hiredate,sal,comm,deptno) VALUES(6666,'yxz','student',7369,CURDATE(),800,100,NULL);

案例:

  • 查询员工及对应的部门信息
  • 这个时候没有部门的员工也显示出来,当然没有员工的部门不会显示,因为是这一条查询以员工表为主去找去部门表查询匹配,如果查询不到,则也会显示该员工的信息,只是没有部门信息而已,详细请看:
mysql 复制代码
SELECT * FROM emp e LEFT OUTER JOIN dept d ON e.deptno=d.deptno;

/*
如下:刚插入的没有部门表,但是左边是员工表,员工表为主么,所以员工信息还会显示出来,但是部门信息不会。
mysql> select * from emp e left outer join dept d on e.deptno=d.deptno;
+-------+--------+-----------+------+------------+------+------+--------+--------+------------+----------+
| empno | ename  | job       | mgr  | hiredate   | sal  | comm | deptno | deptno | dname      | loc      |
+-------+--------+-----------+------+------------+------+------+--------+--------+------------+----------+
|  6666 | yxz    | student   |  777 | 2025-01-19 |  800 |  100 |   NULL |   NULL | NULL       | NULL     |
|  7369 | SMITH  | CLERK     | 7902 | 1980-12-17 |  800 | NULL |     20 |     20 | RESEARCH   | DALLAS   |
|  7499 | ALLEN  | SALESMAN  | 7698 | 1981-02-20 | 1600 |  300 |     30 |     30 | SALES      | CHICAGO  |
|  7521 | WARD   | SALESMAN  | 7698 | 1981-02-22 | 1250 |  500 |     30 |     30 | SALES      | CHICAGO  |
|  7566 | JONES  | MANAGER   | 7839 | 1981-04-02 | 2975 | NULL |     20 |     20 | RESEARCH   | DALLAS   |
|  7654 | MARTIN | SALESMAN  | 7698 | 1981-09-28 | 1250 | 1400 |     30 |     30 | SALES      | CHICAGO  |
|  7698 | BLAKE  | MANAGER   | 7839 | 1981-05-01 | 2850 | NULL |     30 |     30 | SALES      | CHICAGO  |
|  7782 | CLARK  | MANAGER   | 7839 | 1981-06-09 | 2450 | NULL |     10 |     10 | ACCOUNTING | NEW YORK |
|  7788 | SCOTT  | ANALYST   | 7566 | 1987-04-19 | 3000 | NULL |     20 |     20 | RESEARCH   | DALLAS   |
|  7839 | KING   | PRESIDENT | NULL | 1981-11-17 | 5000 | NULL |     10 |     10 | ACCOUNTING | NEW YORK |
|  7844 | TURNER | SALESMAN  | 7698 | 1981-09-08 | 1500 |    0 |     30 |     30 | SALES      | CHICAGO  |
|  7876 | ADAMS  | CLERK     | 7788 | 1987-05-23 | 1100 | NULL |     20 |     20 | RESEARCH   | DALLAS   |
|  7900 | JAMES  | CLERK     | 7698 | 1981-12-03 |  950 | NULL |     30 |     30 | SALES      | CHICAGO  |
|  7902 | FORD   | ANALYST   | 7566 | 1981-12-03 | 3000 | NULL |     20 |     20 | RESEARCH   | DALLAS   |
|  7934 | MILLER | CLERK     | 7782 | 1982-01-23 | 1300 | NULL |     10 |     10 | ACCOUNTING | NEW YORK |
+-------+--------+-----------+------+------------+------+------+--------+--------+------------+----------+
15 rows in set (0.00 sec)
*/
右外连接

在表关系的笛卡尔积中,出了选择相匹配的数据记录,还包含关联右边表中不匹配的数据记录。

这个就是和上面左外连接相反,以第二个表为主,去第一个表找东西,找不到的就在左半边显示全部是空。

案例:

  • 查询员工及对应的部门信息
  • 这个时候就是主要有部门,都显示,员工没有部门,不做显示:
mysql 复制代码
SELECT * FROM emp e RIGHT OUTER JOIN dept d ON e.deptno=d.deptno;

/*
mysql> select * from emp e right outer join dept d on e.deptno=d.deptno;
+-------+--------+-----------+------+------------+------+------+--------+--------+------------+----------+
| empno | ename  | job       | mgr  | hiredate   | sal  | comm | deptno | deptno | dname      | loc      |
+-------+--------+-----------+------+------------+------+------+--------+--------+------------+----------+
|  7934 | MILLER | CLERK     | 7782 | 1982-01-23 | 1300 | NULL |     10 |     10 | ACCOUNTING | NEW YORK |
|  7839 | KING   | PRESIDENT | NULL | 1981-11-17 | 5000 | NULL |     10 |     10 | ACCOUNTING | NEW YORK |
|  7782 | CLARK  | MANAGER   | 7839 | 1981-06-09 | 2450 | NULL |     10 |     10 | ACCOUNTING | NEW YORK |
|  7902 | FORD   | ANALYST   | 7566 | 1981-12-03 | 3000 | NULL |     20 |     20 | RESEARCH   | DALLAS   |
|  7876 | ADAMS  | CLERK     | 7788 | 1987-05-23 | 1100 | NULL |     20 |     20 | RESEARCH   | DALLAS   |
|  7788 | SCOTT  | ANALYST   | 7566 | 1987-04-19 | 3000 | NULL |     20 |     20 | RESEARCH   | DALLAS   |
|  7566 | JONES  | MANAGER   | 7839 | 1981-04-02 | 2975 | NULL |     20 |     20 | RESEARCH   | DALLAS   |
|  7369 | SMITH  | CLERK     | 7902 | 1980-12-17 |  800 | NULL |     20 |     20 | RESEARCH   | DALLAS   |
|  7900 | JAMES  | CLERK     | 7698 | 1981-12-03 |  950 | NULL |     30 |     30 | SALES      | CHICAGO  |
|  7844 | TURNER | SALESMAN  | 7698 | 1981-09-08 | 1500 |    0 |     30 |     30 | SALES      | CHICAGO  |
|  7698 | BLAKE  | MANAGER   | 7839 | 1981-05-01 | 2850 | NULL |     30 |     30 | SALES      | CHICAGO  |
|  7654 | MARTIN | SALESMAN  | 7698 | 1981-09-28 | 1250 | 1400 |     30 |     30 | SALES      | CHICAGO  |
|  7521 | WARD   | SALESMAN  | 7698 | 1981-02-22 | 1250 |  500 |     30 |     30 | SALES      | CHICAGO  |
|  7499 | ALLEN  | SALESMAN  | 7698 | 1981-02-20 | 1600 |  300 |     30 |     30 | SALES      | CHICAGO  |
|  NULL | NULL   | NULL      | NULL | NULL       | NULL | NULL |   NULL |     40 | OPERATIONS | BOSTON   |
+-------+--------+-----------+------+------------+------+------+--------+--------+------------+----------+
15 rows in set (0.00 sec)
*/
全连接

在表关系的笛卡尔积中,出了选择相匹配的数据记录,还包含关联左右两边表中不匹配的数据记录。即全外连接返回两个表中所有匹配和不匹配的行。如果一个表中的一行在另一个表中没有匹配,结果集中也会包含该行,同时在其他表对应的位置填充NULL。

这个在MYSQL中不支持,故不做解释。

自连接

自连接就是指表与其自身进行连接,同样可以看做两张表,只不过两张表一样而已。

案例:

  • 查询每个员工对应的领导姓名。
mysql 复制代码
SELECT e.ename,e.mgr,me.ename '领导' FROM emp e,emp me WHERE e.mgr=me.empno;

/*
mysql> select e.ename, e.mgr, me.ename '领导' from emp e, emp me where e.mgr=me.empno;
+--------+------+-------+
| ename  | mgr  | 领导  |
+--------+------+-------+
| SMITH  | 7902 | FORD  |
| ALLEN  | 7698 | BLAKE |
| WARD   | 7698 | BLAKE |
| JONES  | 7839 | KING  |
| MARTIN | 7698 | BLAKE |
| BLAKE  | 7839 | KING  |
| CLARK  | 7839 | KING  |
| SCOTT  | 7566 | JONES |
| TURNER | 7698 | BLAKE |
| ADAMS  | 7788 | SCOTT |
| JAMES  | 7698 | BLAKE |
| FORD   | 7566 | JONES |
| MILLER | 7782 | CLARK |
+--------+------+-------+
13 rows in set (0.00 sec)
*/

七种JOINS实现

上面的交叉连接、内连接、外连接、等值连接 其实都可以从集合角度来看,而从集合角度来看,一共有7中连接方式,如图所示:

内连接

就是上面的内连接。

左连接

上面的左外连接。

右连接

上面的右外连接。

全连接

案例:

  • 输出员工和其所在部门的所有信息
  • 分析:由于存在有些员工没有部门、有些部门没有员工,之前解决其中一个用的是左外连接和右外连接,但是都是解决其中一个问题的,想要解决全部理论可用全连接 ,但是MYSQL不支持,替代方案:全连接(union),也就是集合运算.
sql 复制代码
SELECT * 
FROM emp e INNER JOIN dept d ON e.deptno = d.deptno;
UNION
SELECT * 
FROM emp e INNER JOIN dept d ON e.deptno IS NULL AND d.deptno IS NULL;

/*
mysql> select * from emp e inner join dept d on e.deptno=d.deptno
    -> union
    -> select * from emp e inner join dept d on e.deptno is null or d.deptno is null;
+-------+--------+-----------+------+------------+------+------+--------+--------+------------+----------+
| empno | ename  | job       | mgr  | hiredate   | sal  | comm | deptno | deptno | dname      | loc      |
+-------+--------+-----------+------+------------+------+------+--------+--------+------------+----------+
|  7369 | SMITH  | CLERK     | 7902 | 1980-12-17 |  800 | NULL |     20 |     20 | RESEARCH   | DALLAS   |
|  7499 | ALLEN  | SALESMAN  | 7698 | 1981-02-20 | 1600 |  300 |     30 |     30 | SALES      | CHICAGO  |
|  7521 | WARD   | SALESMAN  | 7698 | 1981-02-22 | 1250 |  500 |     30 |     30 | SALES      | CHICAGO  |
|  7566 | JONES  | MANAGER   | 7839 | 1981-04-02 | 2975 | NULL |     20 |     20 | RESEARCH   | DALLAS   |
|  7654 | MARTIN | SALESMAN  | 7698 | 1981-09-28 | 1250 | 1400 |     30 |     30 | SALES      | CHICAGO  |
|  7698 | BLAKE  | MANAGER   | 7839 | 1981-05-01 | 2850 | NULL |     30 |     30 | SALES      | CHICAGO  |
|  7782 | CLARK  | MANAGER   | 7839 | 1981-06-09 | 2450 | NULL |     10 |     10 | ACCOUNTING | NEW YORK |
|  7788 | SCOTT  | ANALYST   | 7566 | 1987-04-19 | 3000 | NULL |     20 |     20 | RESEARCH   | DALLAS   |
|  7839 | KING   | PRESIDENT | NULL | 1981-11-17 | 5000 | NULL |     10 |     10 | ACCOUNTING | NEW YORK |
|  7844 | TURNER | SALESMAN  | 7698 | 1981-09-08 | 1500 |    0 |     30 |     30 | SALES      | CHICAGO  |
|  7876 | ADAMS  | CLERK     | 7788 | 1987-05-23 | 1100 | NULL |     20 |     20 | RESEARCH   | DALLAS   |
|  7900 | JAMES  | CLERK     | 7698 | 1981-12-03 |  950 | NULL |     30 |     30 | SALES      | CHICAGO  |
|  7902 | FORD   | ANALYST   | 7566 | 1981-12-03 | 3000 | NULL |     20 |     20 | RESEARCH   | DALLAS   |
|  7934 | MILLER | CLERK     | 7782 | 1982-01-23 | 1300 | NULL |     10 |     10 | ACCOUNTING | NEW YORK |
|  6666 | yxz    | student   |  777 | 2025-01-19 |  800 |  100 |   NULL |     10 | ACCOUNTING | NEW YORK |
|  6666 | yxz    | student   |  777 | 2025-01-19 |  800 |  100 |   NULL |     20 | RESEARCH   | DALLAS   |
|  6666 | yxz    | student   |  777 | 2025-01-19 |  800 |  100 |   NULL |     30 | SALES      | CHICAGO  |
|  6666 | yxz    | student   |  777 | 2025-01-19 |  800 |  100 |   NULL |     40 | OPERATIONS | BOSTON   |
+-------+--------+-----------+------+------------+------+------+--------+--------+------------+----------+
18 rows in set (0.02 sec)
*/

左排除连接

sql 复制代码
#左边,左连接,排除d中不包含e中的信息
SELECT * 
FROM emp e LEFT JOIN dept d ON e.deptno = d.deptno 
WHERE d.deptno IS NULL;

/*
# 我的数据没有哈
mysql> select * from emp e inner join dept d on e.deptno=d.deptno where e.deptno is null;
Empty set (0.00 sec)
*/

右排除连接

sql 复制代码
SELECT * 
FROM emp e RIGHT JOIN dept d ON e.deptno = d.deptno 
WHERE e.deptno IS NULL;

/*
mysql> SELECT *
    -> FROM emp e RIGHT JOIN dept d ON e.deptno = d.deptno
    -> WHERE e.deptno IS NULL;
+-------+-------+------+------+----------+------+------+--------+--------+------------+--------+
| empno | ename | job  | mgr  | hiredate | sal  | comm | deptno | deptno | dname      | loc    |
+-------+-------+------+------+----------+------+------+--------+--------+------------+--------+
|  NULL | NULL  | NULL | NULL | NULL     | NULL | NULL |   NULL |     40 | OPERATIONS | BOSTON |
+-------+-------+------+------+----------+------+------+--------+--------+------------+--------+
1 row in set (0.00 sec)
*/

外部排除连接

sql 复制代码
SELECT * 
FROM emp e INNER JOIN dept d ON e.deptno IS NULL AND d.deptno IS NULL;

/*
mysql> SELECT *
    -> FROM emp e INNER JOIN dept d ON e.deptno IS NULL AND d.deptno IS NULL;
Empty set (0.00 sec)
*/

集合运算

MySQL支持并集运算。

并集即两个集合所有部分

UNION DISTINCT(union 默认)

  1. UNION DISTINCT 会删除重复行
  2. 相同的行在结果中只出现一次。
mysql 复制代码
SELECT * FROM emp
UNION
SELECT * FROM emp WHERE deptno=10;

/*
mysql> SELECT * FROM emp
    -> UNION
    -> SELECT * FROM emp WHERE deptno=10;
+-------+--------+-----------+------+------------+------+------+--------+
| empno | ename  | job       | mgr  | hiredate   | sal  | comm | deptno |
+-------+--------+-----------+------+------------+------+------+--------+
|  6666 | yxz    | student   |  777 | 2025-01-19 |  800 |  100 |   NULL |
|  7369 | SMITH  | CLERK     | 7902 | 1980-12-17 |  800 | NULL |     20 |
|  7499 | ALLEN  | SALESMAN  | 7698 | 1981-02-20 | 1600 |  300 |     30 |
|  7521 | WARD   | SALESMAN  | 7698 | 1981-02-22 | 1250 |  500 |     30 |
|  7566 | JONES  | MANAGER   | 7839 | 1981-04-02 | 2975 | NULL |     20 |
|  7654 | MARTIN | SALESMAN  | 7698 | 1981-09-28 | 1250 | 1400 |     30 |
|  7698 | BLAKE  | MANAGER   | 7839 | 1981-05-01 | 2850 | NULL |     30 |
|  7782 | CLARK  | MANAGER   | 7839 | 1981-06-09 | 2450 | NULL |     10 |
|  7788 | SCOTT  | ANALYST   | 7566 | 1987-04-19 | 3000 | NULL |     20 |
|  7839 | KING   | PRESIDENT | NULL | 1981-11-17 | 5000 | NULL |     10 |
|  7844 | TURNER | SALESMAN  | 7698 | 1981-09-08 | 1500 |    0 |     30 |
|  7876 | ADAMS  | CLERK     | 7788 | 1987-05-23 | 1100 | NULL |     20 |
|  7900 | JAMES  | CLERK     | 7698 | 1981-12-03 |  950 | NULL |     30 |
|  7902 | FORD   | ANALYST   | 7566 | 1981-12-03 | 3000 | NULL |     20 |
|  7934 | MILLER | CLERK     | 7782 | 1982-01-23 | 1300 | NULL |     10 |
+-------+--------+-----------+------+------------+------+------+--------+
15 rows in set (0.00 sec)
*/

UNION ALL

  1. UNION 不会会删除重复行
  2. 相同的行在结果中可能出现多次
mysql 复制代码
SELECT * FROM emp
UNION ALL
SELECT * FROM emp WHERE deptno=10;

/*
mysql> select * from emp
    -> union all
    -> select * from emp where emp.deptno=10;
+-------+--------+-----------+------+------------+------+------+--------+
| empno | ename  | job       | mgr  | hiredate   | sal  | comm | deptno |
+-------+--------+-----------+------+------------+------+------+--------+
|  6666 | yxz    | student   |  777 | 2025-01-19 |  800 |  100 |   NULL |
|  7369 | SMITH  | CLERK     | 7902 | 1980-12-17 |  800 | NULL |     20 |
|  7499 | ALLEN  | SALESMAN  | 7698 | 1981-02-20 | 1600 |  300 |     30 |
|  7521 | WARD   | SALESMAN  | 7698 | 1981-02-22 | 1250 |  500 |     30 |
|  7566 | JONES  | MANAGER   | 7839 | 1981-04-02 | 2975 | NULL |     20 |
|  7654 | MARTIN | SALESMAN  | 7698 | 1981-09-28 | 1250 | 1400 |     30 |
|  7698 | BLAKE  | MANAGER   | 7839 | 1981-05-01 | 2850 | NULL |     30 |
|  7782 | CLARK  | MANAGER   | 7839 | 1981-06-09 | 2450 | NULL |     10 |
|  7788 | SCOTT  | ANALYST   | 7566 | 1987-04-19 | 3000 | NULL |     20 |
|  7839 | KING   | PRESIDENT | NULL | 1981-11-17 | 5000 | NULL |     10 |
|  7844 | TURNER | SALESMAN  | 7698 | 1981-09-08 | 1500 |    0 |     30 |
|  7876 | ADAMS  | CLERK     | 7788 | 1987-05-23 | 1100 | NULL |     20 |
|  7900 | JAMES  | CLERK     | 7698 | 1981-12-03 |  950 | NULL |     30 |
|  7902 | FORD   | ANALYST   | 7566 | 1981-12-03 | 3000 | NULL |     20 |
|  7934 | MILLER | CLERK     | 7782 | 1982-01-23 | 1300 | NULL |     10 |
|  7782 | CLARK  | MANAGER   | 7839 | 1981-06-09 | 2450 | NULL |     10 |
|  7839 | KING   | PRESIDENT | NULL | 1981-11-17 | 5000 | NULL |     10 |
|  7934 | MILLER | CLERK     | 7782 | 1982-01-23 | 1300 | NULL |     10 |
+-------+--------+-----------+------+------------+------+------+--------+
18 rows in set (0.00 sec)
*/

要求

(1)输入的查询不能包含ORDER BY字句,可以为整个集合运算结果选择性地增加一个ORDER BY字句;

(2)两个查询必须包含相同的列数

(3)相应列必须具有兼容的数据类型。兼容个的数据类型:优先级较低的数据类型必须能隐式地转换为较高级的数据类型。比如输入的查询1的第一列为int类型,输入的查询2的第一列为float类型,则较低的数据类型int类型可以隐式地转换为较高级float类型。如果输入的查询1的第一列为char类型,输入的查询2的第一列为datetime类型,则会提示转换失败:从字符串转换日期和/或时间时,转换失败;

(4)集合运算结果中列名由输入的查询1决定,如果要为结果分配结果列,应该在输入的查询1中分配相应的别名;

(5)集合运算时,对行进行比较时,集合运算认为两个NULL相等

多表查询练习

  1. 查询出雇佣日期在1981年的所有员工的编号、姓名、雇佣日期、工作、领导姓名、雇佣月工资、雇佣年工资(基本工资+奖金),工资等级、部门编号、部门名称、部门位置,并且求这些员工的月基本工资在1500~3500之间,将最后的结果按照年工资的降序排列,如果年工资相等,则按照工作进行排序。

需求很多,逐步分析

  • 确定所需要的数据表
    • emp:编号、姓名、雇佣日期,工作、月工资、年薪
    • emp:领导姓名
    • dept:部门编号、名称、位置
    • salgrade:工资等级
  • 确定一致的关联字段
    • 员工和领导:e.mgr=e1.empno
    • 员工和部门:e.deptno=dept.deptno
    • 员工和工资等级:e.sal BETWEEN s.losal AND s.hisal

**步骤一(拆表,先查一张表):**查询出所有在1981年雇佣的雇员编号、姓名、御用日期、工作、月工资、年工资,并且月薪在1500~3500之间。只需要emp单张表即可。

mysql 复制代码
SELECT e.empno,e.ename,e.hiredate,e.sal,(e.sal+IFNULL(e.comm,0))*12 年薪
FROM emp e
WHERE DATE_FORMAT(e.hiredate,'%Y')='1981' AND e.sal BETWEEN  1500 AND 3500;

/*
mysql> select e.empno, e.ename, e.hiredate, e.sal, (e.sal+ifnull(e.comm, 0))*12
    -> from emp e
    -> where date_format(e.hiredate, '%Y')='1981' and e.sal between 1500 and 3500;
+-------+--------+------------+------+------------------------------+
| empno | ename  | hiredate   | sal  | (e.sal+ifnull(e.comm, 0))*12 |
+-------+--------+------------+------+------------------------------+
|  7499 | ALLEN  | 1981-02-20 | 1600 |                        22800 |
|  7566 | JONES  | 1981-04-02 | 2975 |                        35700 |
|  7698 | BLAKE  | 1981-05-01 | 2850 |                        34200 |
|  7782 | CLARK  | 1981-06-09 | 2450 |                        29400 |
|  7844 | TURNER | 1981-09-08 | 1500 |                        18000 |
|  7902 | FORD   | 1981-12-03 | 3000 |                        36000 |
+-------+--------+------------+------+------------------------------+
6 rows in set (0.00 sec)
*/

**步骤二:**加入领导信息,使用自身关联。

mysql 复制代码
SELECT e.empno,e.ename,e.hiredate,e.sal,(e.sal+IFNULL(e.comm,0))*12 年薪,m.ename 领导
FROM emp e,emp m
WHERE DATE_FORMAT(e.hiredate,'%Y')='1981' AND e.sal BETWEEN  1500 AND 3500
AND e.mgr=m.empno;

/*
mysql> select e.empno, e.ename, e.hiredate, e.sal, (e.sal+ifnull(e.comm, 0))*12, m.ename
    -> from emp e, emp m
    -> where date_format(e.hiredate, '%Y')='1981' and e.sal between 1500 and 3500
    -> and e.mgr=m.empno;
+-------+--------+------------+------+------------------------------+-------+
| empno | ename  | hiredate   | sal  | (e.sal+ifnull(e.comm, 0))*12 | ename |
+-------+--------+------------+------+------------------------------+-------+
|  7499 | ALLEN  | 1981-02-20 | 1600 |                        22800 | BLAKE |
|  7566 | JONES  | 1981-04-02 | 2975 |                        35700 | KING  |
|  7698 | BLAKE  | 1981-05-01 | 2850 |                        34200 | KING  |
|  7782 | CLARK  | 1981-06-09 | 2450 |                        29400 | KING  |
|  7844 | TURNER | 1981-09-08 | 1500 |                        18000 | BLAKE |
|  7902 | FORD   | 1981-12-03 | 3000 |                        36000 | JONES |
+-------+--------+------------+------+------------------------------+-------+
6 rows in set (0.00 sec)
*/

**步骤三:**加入部门信息。

mysql 复制代码
SELECT e.empno,e.ename,e.hiredate,e.sal,(e.sal+IFNULL(e.comm,0))*12 年薪,m.ename 领导,d.deptno,d.dname,d.loc
FROM emp e,emp m,dept d
WHERE DATE_FORMAT(e.hiredate,'%Y')='1981' AND e.sal BETWEEN  1500 AND 3500
AND e.mgr=m.empno AND e.deptno=d.deptno;

/*
mysql> select e.empno, e.ename, e.hiredate, e.sal, (e.sal+ifnull(e.comm, 0))*12, m.ename '领导', d.deptno, d.dname, d.lo
c
    -> from emp e, emp m, dept d
    -> where date_format(e.hiredate, '%Y')='1981' and e.sal between 1500 and 3500
    -> and e.mgr=m.empno and e.deptno=d.deptno;
+-------+--------+------------+------+------------------------------+-------+--------+------------+----------+
| empno | ename  | hiredate   | sal  | (e.sal+ifnull(e.comm, 0))*12 | 领导  | deptno | dname      | loc      |
+-------+--------+------------+------+------------------------------+-------+--------+------------+----------+
|  7782 | CLARK  | 1981-06-09 | 2450 |                        29400 | KING  |     10 | ACCOUNTING | NEW YORK |
|  7902 | FORD   | 1981-12-03 | 3000 |                        36000 | JONES |     20 | RESEARCH   | DALLAS   |
|  7566 | JONES  | 1981-04-02 | 2975 |                        35700 | KING  |     20 | RESEARCH   | DALLAS   |
|  7844 | TURNER | 1981-09-08 | 1500 |                        18000 | BLAKE |     30 | SALES      | CHICAGO  |
|  7698 | BLAKE  | 1981-05-01 | 2850 |                        34200 | KING  |     30 | SALES      | CHICAGO  |
|  7499 | ALLEN  | 1981-02-20 | 1600 |                        22800 | BLAKE |     30 | SALES      | CHICAGO  |
+-------+--------+------------+------+------------------------------+-------+--------+------------+----------+
6 rows in set (0.01 sec)
*/

**步骤四:**加入工资等级

mysql 复制代码
SELECT e.empno,e.ename,e.hiredate,e.sal,(e.sal+IFNULL(e.comm,0))*12 年薪,m.ename 领导,d.deptno,d.dname,d.loc,
s.grade
FROM emp e,emp m,dept d,salgrade s
WHERE DATE_FORMAT(e.hiredate,'%Y')='1981' AND e.sal BETWEEN  1500 AND 3500
AND e.mgr=m.empno AND e.deptno=d.deptno
AND e.sal BETWEEN s.losal AND s.hisal;

/*
mysql> select e.empno, e.ename, e.hiredate, e.sal, (e.sal+ifnull(e.comm, 0))*12, m.ename '领导', d.deptno, d.dname, d.loc, s.grade
    -> from emp e, emp m, dept d, salgrade s
    -> where date_format(e.hiredate, '%Y')='1981' and e.sal between 1500 and 3500
    -> and e.mgr=m.empno and e.deptno=d.deptno
    -> and e.sal between s.losal and s.hisal;
+-------+--------+------------+------+------------------------------+-------+--------+------------+----------+-------+
| empno | ename  | hiredate   | sal  | (e.sal+ifnull(e.comm, 0))*12 | 领导  | deptno | dname      | loc      | grade |
+-------+--------+------------+------+------------------------------+-------+--------+------------+----------+-------+
|  7844 | TURNER | 1981-09-08 | 1500 |                        18000 | BLAKE |     30 | SALES      | CHICAGO  |     3 |
|  7499 | ALLEN  | 1981-02-20 | 1600 |                        22800 | BLAKE |     30 | SALES      | CHICAGO  |     3 |
|  7902 | FORD   | 1981-12-03 | 3000 |                        36000 | JONES |     20 | RESEARCH   | DALLAS   |     4 |
|  7782 | CLARK  | 1981-06-09 | 2450 |                        29400 | KING  |     10 | ACCOUNTING | NEW YORK |     4 |
|  7698 | BLAKE  | 1981-05-01 | 2850 |                        34200 | KING  |     30 | SALES      | CHICAGO  |     4 |
|  7566 | JONES  | 1981-04-02 | 2975 |                        35700 | KING  |     20 | RESEARCH   | DALLAS   |     4 |
+-------+--------+------------+------+------------------------------+-------+--------+------------+----------+-------+
6 rows in set (0.00 sec)
*/

**步骤五:**排序

mysql 复制代码
SELECT e.empno,e.ename,e.hiredate,e.sal,(e.sal+IFNULL(e.comm,0))*12 年薪,m.ename 领导,d.deptno,d.dname,d.loc,
s.grade
FROM emp e,emp m,dept d,salgrade s
WHERE DATE_FORMAT(e.hiredate,'%Y')='1981' AND e.sal BETWEEN  1500 AND 3500
AND e.mgr=m.empno AND e.deptno=d.deptno
AND e.sal BETWEEN s.losal AND s.hisal
ORDER BY 年薪 DESC;

/*
mysql> select e.empno, e.ename, e.hiredate, e.sal, (e.sal+ifnull(e.comm, 0))*12 '年薪', m.ename '领导', d.deptno, d.dnam
e, d.loc, s.grade
    -> from emp e, emp m, dept d, salgrade s
    -> where date_format(e.hiredate, '%Y')='1981' and e.sal between 1500 and 3500
    -> and e.mgr=m.empno and e.deptno=d.deptno
    -> and e.sal between s.losal and s.hisal
    -> order by '年薪' desc;
+-------+--------+------------+------+-------+-------+--------+------------+----------+-------+
| empno | ename  | hiredate   | sal  | 年薪  | 领导  | deptno | dname      | loc      | grade |
+-------+--------+------------+------+-------+-------+--------+------------+----------+-------+
|  7844 | TURNER | 1981-09-08 | 1500 | 18000 | BLAKE |     30 | SALES      | CHICAGO  |     3 |
|  7499 | ALLEN  | 1981-02-20 | 1600 | 22800 | BLAKE |     30 | SALES      | CHICAGO  |     3 |
|  7902 | FORD   | 1981-12-03 | 3000 | 36000 | JONES |     20 | RESEARCH   | DALLAS   |     4 |
|  7782 | CLARK  | 1981-06-09 | 2450 | 29400 | KING  |     10 | ACCOUNTING | NEW YORK |     4 |
|  7698 | BLAKE  | 1981-05-01 | 2850 | 34200 | KING  |     30 | SALES      | CHICAGO  |     4 |
|  7566 | JONES  | 1981-04-02 | 2975 | 35700 | KING  |     20 | RESEARCH   | DALLAS   |     4 |
+-------+--------+------------+------+-------+-------+--------+------------+----------+-------+
6 rows in set (0.00 sec)
*/
相关推荐
邓熙榆7 分钟前
Logo语言的网络编程
开发语言·后端·golang
随心Coding9 分钟前
【MySQL】存储引擎有哪些?区别是什么?
数据库·mysql
m0_748237051 小时前
sql实战解析-sum()over(partition by xx order by xx)
数据库·sql
飞的肖1 小时前
日志(elk stack)基础语法学习,零基础学习
学习·elk
dal118网工任子仪2 小时前
61,【1】BUUCTF WEB BUU XSS COURSE 11
前端·数据库·xss
萌小丹Fighting3 小时前
【Postgres_Python】使用python脚本批量创建和导入多个PG数据库
数据库
dal118网工任子仪3 小时前
66,【6】buuctf web [HarekazeCTF2019]Avatar Uploader 1
笔记·学习
青灯文案13 小时前
Oracle 数据库常见字段类型大全及详细解析
数据库·oracle
02苏_3 小时前
2025/1/21 学习Vue的第四天
学习