文章目录
👉基本查询回顾👈
- 查询工资高于 500 或岗位为 MANAGER 的雇员,同时还要满足他们的姓名首字母为大写的 J
sql
mysql> select ename, job, sal from emp where (sal > 500 or job = 'MANAGER') and (substring(ename, 1, 1) = 'J');
+-------+---------+---------+
| ename | job | sal |
+-------+---------+---------+
| JONES | MANAGER | 2975.00 |
| JAMES | CLERK | 950.00 |
+-------+---------+---------+
2 rows in set (0.00 sec)
mysql> select ename, job, sal from emp where (sal > 500 or job = 'MANAGER') and (ename like 'J%');
+-------+---------+---------+
| ename | job | sal |
+-------+---------+---------+
| JONES | MANAGER | 2975.00 |
| JAMES | CLERK | 950.00 |
+-------+---------+---------+
2 rows in set (0.00 sec)
- 按照部门号升序而雇员的工资降序排序
sql
mysql> select deptno, ename, sal from emp order by deptno asc, sal desc;
+--------+--------+---------+
| deptno | ename | sal |
+--------+--------+---------+
| 10 | KING | 5000.00 |
| 10 | CLARK | 2450.00 |
| 10 | MILLER | 1300.00 |
| 20 | SCOTT | 3000.00 |
| 20 | FORD | 3000.00 |
| 20 | JONES | 2975.00 |
| 20 | ADAMS | 1100.00 |
| 20 | SMITH | 800.00 |
| 30 | BLAKE | 2850.00 |
| 30 | ALLEN | 1600.00 |
| 30 | TURNER | 1500.00 |
| 30 | WARD | 1250.00 |
| 30 | MARTIN | 1250.00 |
| 30 | JAMES | 950.00 |
+--------+--------+---------+
14 rows in set (0.00 sec)
- 使用年薪进行降序排序
sql
-- 年薪=月薪*12+奖金
-- 如果奖金为null,则认为奖金为零
mysql> select ename, sal*12+ifnull(comm,0) as 年薪 from emp order by 年薪 desc;
+--------+----------+
| ename | 年薪 |
+--------+----------+
| KING | 60000.00 |
| SCOTT | 36000.00 |
| FORD | 36000.00 |
| JONES | 35700.00 |
| BLAKE | 34200.00 |
| CLARK | 29400.00 |
| ALLEN | 19500.00 |
| TURNER | 18000.00 |
| MARTIN | 16400.00 |
| MILLER | 15600.00 |
| WARD | 15500.00 |
| ADAMS | 13200.00 |
| JAMES | 11400.00 |
| SMITH | 9600.00 |
+--------+----------+
14 rows in set (0.00 sec)
- 显示工资最高的员工的名字和工作岗位
sql
-- select ename, max(sal) from emp; 这条SQL语句
-- 是无符合语法规范的,因为并没有按照ename进行分组
-- 只有出现在group by中的列才能出现在select中
-- 这显然不是我们想要的结果
mysql> select ename, max(sal) from emp group by ename;
+--------+----------+
| ename | max(sal) |
+--------+----------+
| ADAMS | 1100.00 |
| ALLEN | 1600.00 |
| BLAKE | 2850.00 |
| CLARK | 2450.00 |
| FORD | 3000.00 |
| JAMES | 950.00 |
| JONES | 2975.00 |
| KING | 5000.00 |
| MARTIN | 1250.00 |
| MILLER | 1300.00 |
| SCOTT | 3000.00 |
| SMITH | 800.00 |
| TURNER | 1500.00 |
| WARD | 1250.00 |
+--------+----------+
14 rows in set (0.00 sec)
-- 可以先找出最高工资,然后就能将拥有最高工资的人名显示出来
mysql> select max(sal) from emp;
+----------+
| max(sal) |
+----------+
| 5000.00 |
+----------+
1 row in set (0.00 sec)
mysql> select ename, sal 最高工资 from emp where sal = 5000;
+-------+--------------+
| ename | 最高工资 |
+-------+--------------+
| KING | 5000.00 |
+-------+--------------+
1 row in set (0.00 sec)
-- 上面用了两条SQL语句才完成需求,那么可不可以用
-- 一条SQL语句完成需求呢?当然可以
-- 通过嵌套select子查询
mysql> select ename, job from emp where sal = (select max(sal) from emp);
+-------+-----------+
| ename | job |
+-------+-----------+
| KING | PRESIDENT |
+-------+-----------+
1 row in set (0.00 sec)
select 子查询

- 显示工资高于平均工资的员工信息
sql
mysql> select ename, sal from emp where sal > (select avg(sal) from emp);
+-------+---------+
| ename | sal |
+-------+---------+
| JONES | 2975.00 |
| BLAKE | 2850.00 |
| CLARK | 2450.00 |
| SCOTT | 3000.00 |
| KING | 5000.00 |
| FORD | 3000.00 |
+-------+---------+
6 rows in set (0.00 sec)
- 显示每个部门的平均工资和最高工资
sql
mysql> select deptno, format(avg(sal), 2) 平均工资, max(sal) 最高工资 from emp group by deptno;
+--------+--------------+--------------+
| deptno | 平均工资 | 最高工资 |
+--------+--------------+--------------+
| 10 | 2,916.67 | 5000.00 |
| 20 | 2,175.00 | 3000.00 |
| 30 | 1,566.67 | 2850.00 |
+--------+--------------+--------------+
3 rows in set (0.00 sec)
- 显示平均工资低于 2000 的部门号和它的平均工资
sql
-- format会对数据进行格式化,无法再进行与原数据的比较
-- fromat会用不同的编码来呈现原始数据
mysql> select charset(format(1000, 2));
+--------------------------+
| charset(format(1000, 2)) |
+--------------------------+
| utf8 |
+--------------------------+
1 row in set (0.00 sec)
mysql> select charset(1000);
+---------------+
| charset(1000) |
+---------------+
| binary |
+---------------+
1 row in set (0.00 sec)
mysql> select deptno, avg(sal) 平均工资 from emp group by deptno having 平均工资<2000;
+--------+--------------+
| deptno | 平均工资 |
+--------+--------------+
| 30 | 1566.666667 |
+--------+--------------+
1 row in set (0.00 sec)
- 显示每种岗位的雇员总数,平均工资
sql
mysql> select job 岗位, count(*) 人数, format(avg(sal), 2) 平均工资 from emp group by job;
+-----------+--------+--------------+
| 岗位 | 人数 | 平均工资 |
+-----------+--------+--------------+
| ANALYST | 2 | 3,000.00 |
| CLERK | 4 | 1,037.50 |
| MANAGER | 3 | 2,758.33 |
| PRESIDENT | 1 | 5,000.00 |
| SALESMAN | 4 | 1,400.00 |
+-----------+--------+--------------+
5 rows in set (0.00 sec)
👉多表查询👈
实际开发中数据往往来自不同的表,所以需要多表查询。这部分我们用一个简单的公司管理系统,有三张表 emp、dept 和 salgrade 来演示如何进行多表查询。
笛卡尔积
笛卡尔积是一种关系型数据库中的操作,用于将两个表的每一行进行组合,生成一个新的结果集。它将表之间的每个行组合,生成的结果集的行数等于两个表的行数的乘积。
假设有两个表 A 和 B,表 A 有 m 行,表 B 有 n 行,那么它们的笛卡尔积将生成一个包含 m * n 行的结果集。每个结果集的行包含来自表 A 和表 B 的一行组合。
笛卡尔积的计算方式是对两个表进行无条件的连接,即将表 A 的每一行与表 B 的每一行进行组合。结果集中的每一行都代表了表 A 和表 B 中一行的组合。
需要注意的是,笛卡尔积是对两个表进行无条件的连接的,所以新形成的表中的数据可能是一些无效的数据。因此在将两张表形成一张新表时,我们需要设置一些条件来避免数据无效的问题。
其实我们只要 emp 表中的 deptno 等于 dept 表中的 deptno 字段的记录,就能够解决数据无效的问题。
- 显示雇员名、雇员工资以及所在部门的名字
sql
mysql> select emp.ename, emp.sal, dept.dname from emp, dept where emp.deptno = dept.deptno;
+--------+---------+------------+
| ename | sal | dname |
+--------+---------+------------+
| SMITH | 800.00 | RESEARCH |
| ALLEN | 1600.00 | SALES |
| WARD | 1250.00 | SALES |
| JONES | 2975.00 | RESEARCH |
| MARTIN | 1250.00 | SALES |
| BLAKE | 2850.00 | SALES |
| CLARK | 2450.00 | ACCOUNTING |
| SCOTT | 3000.00 | RESEARCH |
| KING | 5000.00 | ACCOUNTING |
| TURNER | 1500.00 | SALES |
| ADAMS | 1100.00 | RESEARCH |
| JAMES | 950.00 | SALES |
| FORD | 3000.00 | RESEARCH |
| MILLER | 1300.00 | ACCOUNTING |
+--------+---------+------------+
14 rows in set (0.00 sec)
- 显示部门号为 10 的部门名,员工名和工资
sql
-- 部门名只在部门表中有,而员工名和工资只有在员工表中有
-- 因此需要将这两表进行组合
mysql> select emp.deptno, emp.ename, emp.sal from emp, dept where emp.deptno = dept.deptno and dept.deptno = 10;
+--------+--------+---------+
| deptno | ename | sal |
+--------+--------+---------+
| 10 | CLARK | 2450.00 |
| 10 | KING | 5000.00 |
| 10 | MILLER | 1300.00 |
+--------+--------+---------+
3 rows in set (0.00 sec)
- 显示各个员工的姓名,工资,及工资级别
sql
mysql> select * from salgrade;
+-------+-------+-------+
| grade | losal | hisal |
+-------+-------+-------+
| 1 | 700 | 1200 |
| 2 | 1201 | 1400 |
| 3 | 1401 | 2000 |
| 4 | 2001 | 3000 |
| 5 | 3001 | 9999 |
+-------+-------+-------+
5 rows in set (0.00 sec)
mysql> select ename, sal, grade from emp, salgrade where sal between losal and hisal;
+--------+---------+-------+
| ename | sal | grade |
+--------+---------+-------+
| SMITH | 800.00 | 1 |
| ALLEN | 1600.00 | 3 |
| WARD | 1250.00 | 2 |
| JONES | 2975.00 | 4 |
| MARTIN | 1250.00 | 2 |
| BLAKE | 2850.00 | 4 |
| CLARK | 2450.00 | 4 |
| SCOTT | 3000.00 | 4 |
| KING | 5000.00 | 5 |
| TURNER | 1500.00 | 3 |
| ADAMS | 1100.00 | 1 |
| JAMES | 950.00 | 1 |
| FORD | 3000.00 | 4 |
| MILLER | 1300.00 | 2 |
+--------+---------+-------+
解决多表查询的思路
先明确题目和哪些表有关,然后将这些表组成成一张有效的表,那么多表查询就变成了单表查询了。
👉自连接👈
自连接是指在一个表中通过连接操作自身的过程。通常,自连接在以下场景中应用:
层级结构:当数据表中的记录之间存在层级关系时,可以使用自连接来查询父节点和子节点之间的关系。例如,组织结构表中的每个记录表示一个员工,记录中包含一个指向上级员工的外键,通过自连接可以查询员工和他们的上级。
关联关系:当表中的记录之间存在关联关系时,可以使用自连接来查找相关记录。例如,一个订单表中包含了订单的主订单号和子订单号,通过自连接可以查询主订单和对应的子订单。
数据比较:当需要比较表中的记录时,可以使用自连接来将表中的记录与其他记录进行比较。例如,可以使用自连接来比较表中不同时间段的记录,或者比较相邻行的记录。
别名使用:自连接还可以用于给表起别名,并对表进行多次引用,以便进行更复杂的查询操作。通过别名,可以在同一个查询中将表作为不同的实体进行引用,从而实现更灵活的查询需求。
sql
-- 两张相同的表没经过重命名,无法进行笛卡尔积
mysql> select * from dept, dept;
ERROR 1066 (42000): Not unique table/alias: 'dept'
-- 两张相同的表经过重命名后,可以进行笛卡尔积
mysql> select * from dept as dt1, dept as dt2;
+--------+------------+----------+--------+------------+----------+
| deptno | dname | loc | deptno | dname | loc |
+--------+------------+----------+--------+------------+----------+
| 10 | ACCOUNTING | NEW YORK | 10 | ACCOUNTING | NEW YORK |
| 20 | RESEARCH | DALLAS | 10 | ACCOUNTING | NEW YORK |
| 30 | SALES | CHICAGO | 10 | ACCOUNTING | NEW YORK |
| 40 | OPERATIONS | BOSTON | 10 | ACCOUNTING | NEW YORK |
| 10 | ACCOUNTING | NEW YORK | 20 | RESEARCH | DALLAS |
| 20 | RESEARCH | DALLAS | 20 | RESEARCH | DALLAS |
| 30 | SALES | CHICAGO | 20 | RESEARCH | DALLAS |
| 40 | OPERATIONS | BOSTON | 20 | RESEARCH | DALLAS |
| 10 | ACCOUNTING | NEW YORK | 30 | SALES | CHICAGO |
| 20 | RESEARCH | DALLAS | 30 | SALES | CHICAGO |
| 30 | SALES | CHICAGO | 30 | SALES | CHICAGO |
| 40 | OPERATIONS | BOSTON | 30 | SALES | CHICAGO |
| 10 | ACCOUNTING | NEW YORK | 40 | OPERATIONS | BOSTON |
| 20 | RESEARCH | DALLAS | 40 | OPERATIONS | BOSTON |
| 30 | SALES | CHICAGO | 40 | OPERATIONS | BOSTON |
| 40 | OPERATIONS | BOSTON | 40 | OPERATIONS | BOSTON |
+--------+------------+----------+--------+------------+----------+
16 rows in set (0.01 sec)
- 显示员工 FORD 的上级领导的编号和姓名
sql
-- mgr是员工领导的编号
-- 使用子查询
mysql> select empno, ename from emp where empno = (select mgr from emp where ename = 'FORD');
+--------+-------+
| empno | ename |
+--------+-------+
| 007566 | JONES |
+--------+-------+
1 row in set (0.00 sec)
-- 使用多表查询(自连接)
-- 员工领导编号等于领导的编号就能够得到一个有效的表
mysql> select leader.empno, leader.ename from emp leader, emp worker where leader.empno = worker.mgr and worker.ename = 'FORD';
+--------+-------+
| empno | ename |
+--------+-------+
| 007566 | JONES |
+--------+-------+
1 row in set (0.00 sec)
👉子查询👈
子查询是指嵌入在其他 SQL 语句中的 select 语句,也叫嵌套查询。
单行子查询
单行子查询是返回一行记录的子查询。
- 显示 SMITH 同一部门的员工
sql
mysql> select * from emp where deptno = (select deptno from emp where ename = 'SMITH');
+--------+-------+---------+------+---------------------+---------+------+--------+
| empno | ename | job | mgr | hiredate | sal | comm | deptno |
+--------+-------+---------+------+---------------------+---------+------+--------+
| 007369 | SMITH | CLERK | 7902 | 1980-12-17 00:00:00 | 800.00 | NULL | 20 |
| 007566 | JONES | MANAGER | 7839 | 1981-04-02 00:00:00 | 2975.00 | NULL | 20 |
| 007788 | SCOTT | ANALYST | 7566 | 1987-04-19 00:00:00 | 3000.00 | NULL | 20 |
| 007876 | ADAMS | CLERK | 7788 | 1987-05-23 00:00:00 | 1100.00 | NULL | 20 |
| 007902 | FORD | ANALYST | 7566 | 1981-12-03 00:00:00 | 3000.00 | NULL | 20 |
+--------+-------+---------+------+---------------------+---------+------+--------+
5 rows in set (0.00 sec)
多行子查询
多行子查询是返回多行记录的子查询。
- 查询和 10 号部门的工作岗位相同的雇员的名字,岗位,工资,部门号,但是不包含 10 自己的
sql
mysql> select ename, job, sal, deptno from emp where job in (select distinct job from emp where deptno=10) and deptno!=10;
+-------+---------+---------+--------+
| ename | job | sal | deptno |
+-------+---------+---------+--------+
| JONES | MANAGER | 2975.00 | 20 |
| BLAKE | MANAGER | 2850.00 | 30 |
| SMITH | CLERK | 800.00 | 20 |
| ADAMS | CLERK | 1100.00 | 20 |
| JAMES | CLERK | 950.00 | 30 |
+-------+---------+---------+--------+
5 rows in set (0.01 sec)
-- select distinct job from emp where deptno=10 的返
-- 回结果是10号部门中所包含的岗位
-- in关键字是用来判断job是否在10号部门所包含的岗位集合中,如果在则为真
- 显示工资比部门 30 的所有员工的工资高的员工的姓名、工资和部门号
sql
-- 30号部门的员工的最高工资
mysql> select max(sal) from emp where deptno=30;
+----------+
| max(sal) |
+----------+
| 2850.00 |
+----------+
1 row in set (0.00 sec)
mysql> select ename, sal, deptno from emp where sal > (select max(sal) from emp where deptno=30);
+-------+---------+--------+
| ename | sal | deptno |
+-------+---------+--------+
| JONES | 2975.00 | 20 |
| SCOTT | 3000.00 | 20 |
| KING | 5000.00 | 10 |
| FORD | 3000.00 | 20 |
+-------+---------+--------+
4 rows in set (0.00 sec)
mysql> select ename, sal, deptno from emp where sal > all(select sal from emp where deptno=30);
+-------+---------+--------+
| ename | sal | deptno |
+-------+---------+--------+
| JONES | 2975.00 | 20 |
| SCOTT | 3000.00 | 20 |
| KING | 5000.00 | 10 |
| FORD | 3000.00 | 20 |
+-------+---------+--------+
4 rows in set (0.00 sec)
-- select sal from emp where deptno=30 的返回结果是单列多行的数据,这些数据组成了一个集合
- 显示工资比部门 30 的任意员工的工资高的员工的姓名、工资和部门号(包含自己部门的员工)
sql
-- 30号部门的最低工资
mysql> select min(sal) from emp where deptno=30;
+----------+
| min(sal) |
+----------+
| 950.00 |
+----------+
1 row in set (0.00 sec)
mysql> select ename, sal, deptno from emp where sal > (select min(sal) from emp where deptno=30);
+--------+---------+--------+
| ename | sal | deptno |
+--------+---------+--------+
| ALLEN | 1600.00 | 30 |
| WARD | 1250.00 | 30 |
| JONES | 2975.00 | 20 |
| MARTIN | 1250.00 | 30 |
| BLAKE | 2850.00 | 30 |
| CLARK | 2450.00 | 10 |
| SCOTT | 3000.00 | 20 |
| KING | 5000.00 | 10 |
| TURNER | 1500.00 | 30 |
| ADAMS | 1100.00 | 20 |
| FORD | 3000.00 | 20 |
| MILLER | 1300.00 | 10 |
+--------+---------+--------+
12 rows in set (0.00 sec)
mysql> select ename, sal, deptno from emp where sal > any(select sal from emp where deptno=30);
+--------+---------+--------+
| ename | sal | deptno |
+--------+---------+--------+
| ALLEN | 1600.00 | 30 |
| WARD | 1250.00 | 30 |
| JONES | 2975.00 | 20 |
| MARTIN | 1250.00 | 30 |
| BLAKE | 2850.00 | 30 |
| CLARK | 2450.00 | 10 |
| SCOTT | 3000.00 | 20 |
| KING | 5000.00 | 10 |
| TURNER | 1500.00 | 30 |
| ADAMS | 1100.00 | 20 |
| FORD | 3000.00 | 20 |
| MILLER | 1300.00 | 10 |
+--------+---------+--------+
12 rows in set (0.00 sec)
多列子查询
单行子查询是指子查询只返回单列,单行数据;多行子查询是指返回单列多行数据,都是针对单列而言的;而多列子查询则是指查询返回多个列数据的子查询语句。
- 查询和 SMITH 的部门和岗位完全相同的所有雇员,不含 SMITH 本人
sql
-- 查看SMITH所在的部门和岗位
mysql> select job, deptno from emp where ename='SMITH';
+-------+--------+
| job | deptno |
+-------+--------+
| CLERK | 20 |
+-------+--------+
1 row in set (0.00 sec)
mysql> select ename, job, deptno from emp where (job, deptno) = (select job, deptno from emp where ename='SMITH') and ename!='SMITH';
+-------+-------+--------+
| ename | job | deptno |
+-------+-------+--------+
| ADAMS | CLERK | 20 |
+-------+-------+--------+
1 row in set (0.00 sec)
在from子句中使用子查询
子查询语句出现在 from 子句中。这里要用到数据查询的技巧,把一个子查询当做一个临时表使用。
sql
-- 使用select语句形成的表也可以被看做一张表,尽管这张表
-- 并不在磁盘中真实存在,同时我们也就有对这张表进行重命名
-- 也可以其他的表进行笛卡尔积
mysql> select * from emp where deptno=20;
+--------+-------+---------+------+---------------------+---------+------+--------+
| empno | ename | job | mgr | hiredate | sal | comm | deptno |
+--------+-------+---------+------+---------------------+---------+------+--------+
| 007369 | SMITH | CLERK | 7902 | 1980-12-17 00:00:00 | 800.00 | NULL | 20 |
| 007566 | JONES | MANAGER | 7839 | 1981-04-02 00:00:00 | 2975.00 | NULL | 20 |
| 007788 | SCOTT | ANALYST | 7566 | 1987-04-19 00:00:00 | 3000.00 | NULL | 20 |
| 007876 | ADAMS | CLERK | 7788 | 1987-05-23 00:00:00 | 1100.00 | NULL | 20 |
| 007902 | FORD | ANALYST | 7566 | 1981-12-03 00:00:00 | 3000.00 | NULL | 20 |
+--------+-------+---------+------+---------------------+---------+------+--------+
5 rows in set (0.00 sec)
mysql> select * from (select * from emp where deptno=20) as temp where ename='SMITH';
+--------+-------+-------+------+---------------------+--------+------+--------+
| empno | ename | job | mgr | hiredate | sal | comm | deptno |
+--------+-------+-------+------+---------------------+--------+------+--------+
| 007369 | SMITH | CLERK | 7902 | 1980-12-17 00:00:00 | 800.00 | NULL | 20 |
+--------+-------+-------+------+---------------------+--------+------+--------+
1 row in set (0.00 sec)
结论:MySQL 表的大一统思想:不管我们有多少张表,所有通过 select 查出来的结果,都是一张表。
- 显示每个高于自己部门平均工资的员工的姓名、部门、工资、平均工资
sql
-- 获取各个部门的平均工资,将其看作临时表
mysql> select deptno, format(avg(sal), 2) myavg from emp group by deptno;
+--------+----------+
| deptno | myavg |
+--------+----------+
| 10 | 2,916.67 |
| 20 | 2,175.00 |
| 30 | 1,566.67 |
+--------+----------+
3 rows in set (0.00 sec)
mysql> select ename, emp.deptno, sal, format(myavg,2) from (emp, (select deptno, avg(sal) myavg from emp group by deptno) as temp)
-> where emp.deptno = temp.deptno and sal > myavg;
+-------+--------+---------+-----------------+
| ename | deptno | sal | format(myavg,2) |
+-------+--------+---------+-----------------+
| ALLEN | 30 | 1600.00 | 1,566.67 |
| JONES | 20 | 2975.00 | 2,175.00 |
| BLAKE | 30 | 2850.00 | 1,566.67 |
| SCOTT | 20 | 3000.00 | 2,175.00 |
| KING | 10 | 5000.00 | 2,916.67 |
| FORD | 20 | 3000.00 | 2,175.00 |
+-------+--------+---------+-----------------+
6 rows in set (0.00 sec)
-- 在上面的表的基础上,再列出这些人的薪资等级
mysql> select * from salgrade, (select ename, emp.deptno, sal, format(myavg,2) from (emp, (select deptno, avg(sal) myavg from emp group by deptno) as temp)
-> where emp.deptno = temp.deptno and sal > myavg) as ret where ret.sal between losal and hisal;
+-------+-------+-------+-------+--------+---------+-----------------+
| grade | losal | hisal | ename | deptno | sal | format(myavg,2) |
+-------+-------+-------+-------+--------+---------+-----------------+
| 3 | 1401 | 2000 | ALLEN | 30 | 1600.00 | 1,566.67 |
| 4 | 2001 | 3000 | JONES | 20 | 2975.00 | 2,175.00 |
| 4 | 2001 | 3000 | BLAKE | 30 | 2850.00 | 1,566.67 |
| 4 | 2001 | 3000 | SCOTT | 20 | 3000.00 | 2,175.00 |
| 5 | 3001 | 9999 | KING | 10 | 5000.00 | 2,916.67 |
| 4 | 2001 | 3000 | FORD | 20 | 3000.00 | 2,175.00 |
+-------+-------+-------+-------+--------+---------+-----------------+
6 rows in set (0.00 sec)
- 查找每个部门工资最高的人的姓名、工资、部门
sql
mysql> select deptno, max(sal) mymax from emp group by deptno;
+--------+---------+
| deptno | mymax |
+--------+---------+
| 10 | 5000.00 |
| 20 | 3000.00 |
| 30 | 2850.00 |
+--------+---------+
3 rows in set (0.00 sec)
mysql> select emp.ename, emp.sal, emp.deptno from emp, (select deptno, max(sal) mymax from emp group by deptno) as temp
-> where emp.deptno=temp.deptno and emp.sal=temp.mymax;
+-------+---------+--------+
| ename | sal | deptno |
+-------+---------+--------+
| BLAKE | 2850.00 | 30 |
| SCOTT | 3000.00 | 20 |
| KING | 5000.00 | 10 |
| FORD | 3000.00 | 20 |
+-------+---------+--------+
4 rows in set (0.00 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.00 sec)
mysql> select dept.deptno, dname, loc, ename, sal from dept, (select emp.ename, emp.sal, emp.deptno from emp,
> (select deptno, max(sal) mymax from emp group by depttno) as temp where emp.deptno=temp.deptno and emp.sal=temp.mymax) as ret
> where ret.deptno = dept.deptno;
+--------+------------+----------+-------+---------+
| deptno | dname | loc | ename | sal |
+--------+------------+----------+-------+---------+
| 30 | SALES | CHICAGO | BLAKE | 2850.00 |
| 20 | RESEARCH | DALLAS | SCOTT | 3000.00 |
| 10 | ACCOUNTING | NEW YORK | KING | 5000.00 |
| 20 | RESEARCH | DALLAS | FORD | 3000.00 |
+--------+------------+----------+-------+---------+
4 rows in set (0.00 sec)
- 显示每个部门的信息(部门名,编号,地址)和人员数量
sql
mysql> select dname, dept.deptno, loc, num from dept, (select deptno, count(*) num from emp group by deptno) temp
-> where dept.deptno = temp.deptno;
+------------+--------+----------+-----+
| dname | deptno | loc | num |
+------------+--------+----------+-----+
| ACCOUNTING | 10 | NEW YORK | 3 |
| RESEARCH | 20 | DALLAS | 5 |
| SALES | 30 | CHICAGO | 6 |
+------------+--------+----------+-----+
3 rows in set (0.00 sec)
合并查询
在实际应用中,为了合并多个 select 的执行结果,可以使用集合操作符 union,union all。
union
该操作符用于取得两个结果集的并集。当使用该操作符时,会自动去掉结果集中的重复行。
- 将工资大于 2500 或职位是 MANAGER 的人找出来
sql
-- 有些人既是MANAGER,工资也是超过2500
-- 此时就会存在重复的数据,而union会将重
-- 复的数据去重掉,只保留一条数据
mysql> select ename, sal, job from emp where sal > 2500 union
-> select ename, sal, job from emp where job = 'MANAGER';
+-------+---------+-----------+
| ename | sal | job |
+-------+---------+-----------+
| JONES | 2975.00 | MANAGER |
| BLAKE | 2850.00 | MANAGER |
| SCOTT | 3000.00 | ANALYST |
| KING | 5000.00 | PRESIDENT |
| FORD | 3000.00 | ANALYST |
| CLARK | 2450.00 | MANAGER |
+-------+---------+-----------+
6 rows in set (0.00 sec)
union all
该操作符用于取得两个结果集的并集。当使用该操作符时,不会去掉结果集中的重复行。
- 将工资大于 2500 或职位是 MANAGER 的人找出来
sql
-- 可以看到JONES和BLAKE的数据是重复的
mysql> select ename, sal, job from emp where sal > 2500 union all
-> select ename, sal, job from emp where job = 'MANAGER';
+-------+---------+-----------+
| ename | sal | job |
+-------+---------+-----------+
| JONES | 2975.00 | MANAGER |
| BLAKE | 2850.00 | MANAGER |
| SCOTT | 3000.00 | ANALYST |
| KING | 5000.00 | PRESIDENT |
| FORD | 3000.00 | ANALYST |
| JONES | 2975.00 | MANAGER |
| BLAKE | 2850.00 | MANAGER |
| CLARK | 2450.00 | MANAGER |
+-------+---------+-----------+
8 rows in set (0.00 sec)
union 和 union all 的本质就是将多个结果合并成一个结果,也就是将多张表合并成一张表。不过需要注意的是,多张表的列属性需要是一致的。
👉总结👈
本篇博客主要讲解了多表查询、自连接和子查询等等。以上就是本篇博客的全部内容了,如果大家觉得有收获的话,可以点个三连支持一下!谢谢大家啦!💖💝❣️