复合查询
# 基本查询
mysql> show dept;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that correspoL server version for the right syntax to use near 'dept' at line 1
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 * from emp;
+--------+--------+-----------+------+---------------------+---------+---------+--------
| empno | ename | job | mgr | hiredate | sal | comm | deptno
+--------+--------+-----------+------+---------------------+---------+---------+--------
| 007369 | SMITH | CLERK | 7902 | 1980-12-17 00:00:00 | 800.00 | NULL | 20
| 007499 | ALLEN | SALESMAN | 7698 | 1981-02-20 00:00:00 | 1600.00 | 300.00 | 30
| 007521 | WARD | SALESMAN | 7698 | 1981-02-22 00:00:00 | 1250.00 | 500.00 | 30
| 007566 | JONES | MANAGER | 7839 | 1981-04-02 00:00:00 | 2975.00 | NULL | 20
| 007654 | MARTIN | SALESMAN | 7698 | 1981-09-28 00:00:00 | 1250.00 | 1400.00 | 30
| 007698 | BLAKE | MANAGER | 7839 | 1981-05-01 00:00:00 | 2850.00 | NULL | 30
| 007782 | CLARK | MANAGER | 7839 | 1981-06-09 00:00:00 | 2450.00 | NULL | 10
| 007788 | SCOTT | ANALYST | 7566 | 1987-04-19 00:00:00 | 3000.00 | NULL | 20
| 007839 | KING | PRESIDENT | NULL | 1981-11-17 00:00:00 | 5000.00 | NULL | 10
| 007844 | TURNER | SALESMAN | 7698 | 1981-09-08 00:00:00 | 1500.00 | 0.00 | 30
| 007876 | ADAMS | CLERK | 7788 | 1987-05-23 00:00:00 | 1100.00 | NULL | 20
| 007900 | JAMES | CLERK | 7698 | 1981-12-03 00:00:00 | 950.00 | NULL | 30
| 007902 | FORD | ANALYST | 7566 | 1981-12-03 00:00:00 | 3000.00 | NULL | 20
| 007934 | MILLER | CLERK | 7782 | 1982-01-23 00:00:00 | 1300.00 | NULL | 10
+--------+--------+-----------+------+---------------------+---------+---------+--------
14 rows in set (0.00 sec)
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)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
查询工资高于500或岗位为MANAGER的员工,同时要求员工姓名的首字母为大写的J
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)
2
3
4
5
6
7
8
查询员工信息,按部门号升序而员工工资降序显示
mysql> select ename,deptno, sal from emp order by deptno asc, sal desc;
+--------+--------+---------+
| ename | deptno | sal |
+--------+--------+---------+
| KING | 10 | 5000.00 |
| CLARK | 10 | 2450.00 |
| MILLER | 10 | 1300.00 |
| SCOTT | 20 | 3000.00 |
| FORD | 20 | 3000.00 |
| JONES | 20 | 2975.00 |
| ADAMS | 20 | 1100.00 |
| SMITH | 20 | 800.00 |
| BLAKE | 30 | 2850.00 |
| ALLEN | 30 | 1600.00 |
| TURNER | 30 | 1500.00 |
| WARD | 30 | 1250.00 |
| MARTIN | 30 | 1250.00 |
| JAMES | 30 | 950.00 |
+--------+--------+---------+
14 rows in set (0.00 sec)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
查询员工信息,按年薪降序显示
mysql> select ename, (sal*12+ifnull(0, comm)) 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 | 19200.00 |
| TURNER | 18000.00 |
| MILLER | 15600.00 |
| WARD | 15000.00 |
| MARTIN | 15000.00 |
| ADAMS | 13200.00 |
| JAMES | 11400.00 |
| SMITH | 9600.00 |
+--------+----------+
14 rows in set (0.00 sec)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
查询工资最高的员工的姓名和岗位
mysql> select ename, sal from emp where sal=(select max(sal) from emp);
+-------+---------+
| ename | sal |
+-------+---------+
| KING | 5000.00 |
+-------+---------+
2
3
4
5
6
查询工资高于平均工资的员工
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 |
+-------+---------+
2
3
4
5
6
7
8
9
10
11
查询每个部门的平均工资和最高工资
mysql> select deptno, avg(sal), max(sal) from emp group by deptno order by deptno;
+--------+-------------+----------+
| deptno | avg(sal) | max(sal) |
+--------+-------------+----------+
| 10 | 2916.666667 | 5000.00 |
| 20 | 2175.000000 | 3000.00 |
| 30 | 1566.666667 | 2850.00 |
+--------+-------------+----------+
3 rows in set (0.01 sec)
2
3
4
5
6
7
8
9
查询平均工资低于2000的部门号和它的平均工资
mysql> select deptno, avg(sal) from emp group by deptno having avg(sal)<2000;
+--------+-------------+
| deptno | avg(sal) |
+--------+-------------+
| 30 | 1566.666667 |
+--------+-------------+
1 row in set (0.00 sec)
2
3
4
5
6
7
查询每种岗位的雇员总数和平均工资
mysql> select job, count(job), avg(sal)from emp group by job;
+-----------+------------+-------------+
| job | count(job) | avg(sal) |
+-----------+------------+-------------+
| CLERK | 4 | 1037.500000 |
| SALESMAN | 4 | 1400.000000 |
| MANAGER | 3 | 2758.333333 |
| ANALYST | 2 | 3000.000000 |
| PRESIDENT | 1 | 5000.000000 |
+-----------+------------+-------------+
2
3
4
5
6
7
8
9
10
# 多表查询
不同的表进行笛卡尔积拼接为一张表
- 上面的基础查询都是在一张表的基础上进行的查询,而实际开发中往往需要将多张表关联起来进行查询,这就叫做多表查询。
- 在进行多表查询时,只需要将多张表的表名依次放到from子句之后,用逗号隔开即可,这时MySQL将会对给定的这多张表取笛卡尔积,作为多表查询的初始数据源。
- 多表查询的本质,就是对给定的多张表取笛卡尔积,然后在笛卡尔积中进行查询。
- 多张表中可能会存在相同的列名,这时在选中列名时需要通过表名.列名的方式进行指明
通过多表查询,将emp
和dept
结合为一张表:
mysql> select * from emp, dept where emp.deptno=dept.deptno;
+--------+--------+-----------+------+---------------------+---------+---------+--------+--------+------------+----------+
| empno | ename | job | mgr | hiredate | sal | comm | deptno | deptno | dname | loc |
+--------+--------+-----------+------+---------------------+---------+---------+--------+--------+------------+----------+
| 007369 | SMITH | CLERK | 7902 | 1980-12-17 00:00:00 | 800.00 | NULL | 20 | 20 | RESEARCH | DALLAS |
| 007499 | ALLEN | SALESMAN | 7698 | 1981-02-20 00:00:00 | 1600.00 | 300.00 | 30 | 30 | SALES | CHICAGO |
| 007521 | WARD | SALESMAN | 7698 | 1981-02-22 00:00:00 | 1250.00 | 500.00 | 30 | 30 | SALES | CHICAGO |
| 007566 | JONES | MANAGER | 7839 | 1981-04-02 00:00:00 | 2975.00 | NULL | 20 | 20 | RESEARCH | DALLAS |
| 007654 | MARTIN | SALESMAN | 7698 | 1981-09-28 00:00:00 | 1250.00 | 1400.00 | 30 | 30 | SALES | CHICAGO |
| 007698 | BLAKE | MANAGER | 7839 | 1981-05-01 00:00:00 | 2850.00 | NULL | 30 | 30 | SALES | CHICAGO |
| 007782 | CLARK | MANAGER | 7839 | 1981-06-09 00:00:00 | 2450.00 | NULL | 10 | 10 | ACCOUNTING | NEW YORK |
| 007788 | SCOTT | ANALYST | 7566 | 1987-04-19 00:00:00 | 3000.00 | NULL | 20 | 20 | RESEARCH | DALLAS |
| 007839 | KING | PRESIDENT | NULL | 1981-11-17 00:00:00 | 5000.00 | NULL | 10 | 10 | ACCOUNTING | NEW YORK |
| 007844 | TURNER | SALESMAN | 7698 | 1981-09-08 00:00:00 | 1500.00 | 0.00 | 30 | 30 | SALES | CHICAGO |
| 007876 | ADAMS | CLERK | 7788 | 1987-05-23 00:00:00 | 1100.00 | NULL | 20 | 20 | RESEARCH | DALLAS |
| 007900 | JAMES | CLERK | 7698 | 1981-12-03 00:00:00 | 950.00 | NULL | 30 | 30 | SALES | CHICAGO |
| 007902 | FORD | ANALYST | 7566 | 1981-12-03 00:00:00 | 3000.00 | NULL | 20 | 20 | RESEARCH | DALLAS |
| 007934 | MILLER | CLERK | 7782 | 1982-01-23 00:00:00 | 1300.00 | NULL | 10 | 10 | ACCOUNTING | NEW YORK |
+--------+--------+-----------+------+---------------------+---------+---------+--------+--------+------------+----------+
14 rows in set (0.00 sec)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
显示部门号为10的部门名、员工名和员工工资
由于部门名只有部门表中才有,而员工名和员工工资只有员工表中才有,因此需要同时使用员工表和部门表进行多表查询,在where子句中指明筛选条件为员工的部门号等于部门编号,并且部门号为10的记录:
mysql> select emp.ename,dept.dname,emp.sal from emp, dept where emp.deptno=dept.deptno and emp.deptno=10;
+--------+------------+---------+
| ename | dname | sal |
+--------+------------+---------+
| CLARK | ACCOUNTING | 2450.00 |
| KING | ACCOUNTING | 5000.00 |
| MILLER | ACCOUNTING | 1300.00 |
+--------+------------+---------+
2
3
4
5
6
7
8
显示各个员工的姓名、工资和工资级别
由于员工名和工资只有员工表中才有,而工资级别只有工资等级表中才有,因此需要同时使用员工表和工资等级表进行多表查询,在where子句中指明筛选条件为员工的工资在losal和hisal之间的记录:
mysql> select emp.ename, emp.sal, salgrade.grade from emp, salgrade where emp.sal>=salgrade.losal and emp.sal<=salgrade.hisal order by grade;
+--------+---------+-------+
| ename | sal | grade |
+--------+---------+-------+
| SMITH | 800.00 | 1 |
| ADAMS | 1100.00 | 1 |
| JAMES | 950.00 | 1 |
| WARD | 1250.00 | 2 |
| MARTIN | 1250.00 | 2 |
| MILLER | 1300.00 | 2 |
| ALLEN | 1600.00 | 3 |
| TURNER | 1500.00 | 3 |
| JONES | 2975.00 | 4 |
| BLAKE | 2850.00 | 4 |
| CLARK | 2450.00 | 4 |
| SCOTT | 3000.00 | 4 |
| FORD | 3000.00 | 4 |
| KING | 5000.00 | 5 |
+--------+---------+-------+
14 rows in set (0.00 sec)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 自连接
同一张表进行笛卡尔积拼接为一张表
- 自连接是指在同一张表进行连接查询,也就是说我们不仅可以取不同表的笛卡尔积,也可以对同一张表取笛卡尔积。
- 如果一张表中的某个字段能够将表中的多条记录关联起来,那么就可以通过自连接将表中通过该字段关联的记录组合起来。
- 由于自连接是对同一张表取笛卡尔积,因此在自连接时至少需要给一张表取别名,否则无法区分这两张表中的列。
显示员工FORD的上级领导的编号和姓名
解决该问题可以使用子查询,先对员工表进行查询得到FORD的领导的编号,然后再根据领导的编号对员工表进行查询得到FORD领导的姓名。如下:
- 方式1:
mysql> select ename, empno from emp where empno=(select mgr from emp where ename='FORD');
+-------+--------+
| ename | empno |
+-------+--------+
| JONES | 007566 |
+-------+--------+
1 row in set (0.00 sec)
2
3
4
5
6
7
- 方式2:
mysql> select e2.ename, e2.empno from emp e1, emp e2 where e1.ename='FORD' and e1.mgr=e2.empno;
+-------+--------+
| ename | empno |
+-------+--------+
| JONES | 007566 |
+-------+--------+
1 row in set (0.00 sec)
2
3
4
5
6
7
# 子查询
- 子查询是指嵌入在其他SQL语句中的查询语句,也叫嵌套查询。
- 子查询可分为单行子查询、多行子查询、多列子查询,以及在from子句中使用的子查询
# 单行子查询
单行子查询,是指返回单行单列数据的子查询。
显示SMITH同一部门的员工
mysql> select * from emp where deptno=(select deptno from emp where ename='SMITH') and ename!='SMITH';
+--------+-------+---------+------+---------------------+---------+------+--------+
| empno | ename | job | mgr | hiredate | sal | comm | deptno |
+--------+-------+---------+------+---------------------+---------+------+--------+
| 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 |
+--------+-------+---------+------+---------------------+---------+------+--------+
4 rows in set (0.00 sec)
2
3
4
5
6
7
8
9
10
# 多行子查询
多行子查询是指返回多行单列数据的子查询。
- in关键字:in关键字用于判断一个值是否在指定的子查询中,如果存在则返回true,否则返回false。
- any关键字:any关键字用于判断一个值是否在指定的子查询中,如果存在则返回true,否则返回false。
- all关键字:all关键字用于判断一个值是否在指定的子查询中,如果存在则返回true,否则返回false。
显示和10号部门的工作岗位相同的员工的名字、岗位、工资和部门号,但是不包含10号部门的员工
mysql> select ename, job, sal, deptno from emp where job in (select job from emp where deptno=10);
+--------+-----------+---------+--------+
| ename | job | sal | deptno |
+--------+-----------+---------+--------+
| SMITH | CLERK | 800.00 | 20 |
| JONES | MANAGER | 2975.00 | 20 |
| BLAKE | MANAGER | 2850.00 | 30 |
| CLARK | MANAGER | 2450.00 | 10 |
| KING | PRESIDENT | 5000.00 | 10 |
| ADAMS | CLERK | 1100.00 | 20 |
| JAMES | CLERK | 950.00 | 30 |
| MILLER | CLERK | 1300.00 | 10 |
+--------+-----------+---------+--------+
8 rows in set (0.00 sec)
2
3
4
5
6
7
8
9
10
11
12
13
14
显示工资比30号部门的所有员工的工资高的员工的姓名、工资和部门号
mysql> select ename, job, sal from emp where sal>all (select max(sal) from emp where deptno=30);
+-------+-----------+---------+
| ename | job | sal |
+-------+-----------+---------+
| JONES | MANAGER | 2975.00 |
| SCOTT | ANALYST | 3000.00 |
| KING | PRESIDENT | 5000.00 |
| FORD | ANALYST | 3000.00 |
+-------+-----------+---------+
4 rows in set (0.00 sec)
2
3
4
5
6
7
8
9
10
显示工资比30号部门的任意员工的工资高的员工的姓名、工资和部门号,包含30号部门的员工
mysql> select ename, sal, job, deptno from emp where sal > any(select sal from emp where deptno=30);
+--------+---------+-----------+--------+
| ename | sal | job | deptno |
+--------+---------+-----------+--------+
| ALLEN | 1600.00 | SALESMAN | 30 |
| WARD | 1250.00 | SALESMAN | 30 |
| JONES | 2975.00 | MANAGER | 20 |
| MARTIN | 1250.00 | SALESMAN | 30 |
| BLAKE | 2850.00 | MANAGER | 30 |
| CLARK | 2450.00 | MANAGER | 10 |
| SCOTT | 3000.00 | ANALYST | 20 |
| KING | 5000.00 | PRESIDENT | 10 |
| TURNER | 1500.00 | SALESMAN | 30 |
| ADAMS | 1100.00 | CLERK | 20 |
| FORD | 3000.00 | ANALYST | 20 |
| MILLER | 1300.00 | CLERK | 10 |
+--------+---------+-----------+--------+
12 rows in set (0.00 sec)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 多列子查询
多列子查询是指返回多列多行的子查询。
- 多列子查询得到的结果是多列数据,在比较多列数据时需要将待比较的多个列用圆括号括起来。
- 多列子查询返回的如果是多行数据,在筛选数据时也可以使用in、all和any关键字。
显示和SMITH的部门和岗位完全相同的员工,不包含SMITH本人
mysql> select * from emp where (job, deptno)=(select job, deptno from emp where ename='SMITH') and ename!='SMITH';
+--------+-------+-------+------+---------------------+---------+------+--------+
| empno | ename | job | mgr | hiredate | sal | comm | deptno |
+--------+-------+-------+------+---------------------+---------+------+--------+
| 007876 | ADAMS | CLERK | 7788 | 1987-05-23 00:00:00 | 1100.00 | NULL | 20 |
+--------+-------+-------+------+---------------------+---------+------+--------+
1 row in set (0.00 sec)
2
3
4
5
6
7
# from子句中使用的子查询
from子句中使用的子查询是指在from子句中使用的子查询。
- 子查询语句不仅可以出现在where子句中,也可以出现在from子句中。
- 子查询语句出现from子句中,其查询结果将会被当作一个临时表使用。
- 在from子句中使用子查询时,必须给子查询得到的临时表取一个别名,否则查询将会出错。
显示每个高于自己部门平均工资的员工的姓名、部门、工资和部门的平均工资
mysql> select emp.ename, emp.sal, emp.deptno, temp.avgsal from emp,(select deptno, avg(sal) as avgsal from emp grouup by deptno) temp where emp.deptno=temp.deptno and emp.sal>temp.avgsal;
+-------+---------+--------+-------------+
| ename | sal | deptno | avgsal |
+-------+---------+--------+-------------+
| ALLEN | 1600.00 | 30 | 1566.666667 |
| JONES | 2975.00 | 20 | 2175.000000 |
| BLAKE | 2850.00 | 30 | 1566.666667 |
| SCOTT | 3000.00 | 20 | 2175.000000 |
| KING | 5000.00 | 10 | 2916.666667 |
| FORD | 3000.00 | 20 | 2175.000000 |
+-------+---------+--------+-------------+
6 rows in set (0.00 sec)
2
3
4
5
6
7
8
9
10
11
12
显示每个部门工资最高的员工的姓名、工资、部门和部门的最高工资
mysql> select emp.ename, emp.sal, emp.deptno, temp.maxsal from emp, (select deptno, max(sal) as maxsal from emp grroup by deptno) temp where emp.deptno=temp.deptno and emp.sal=maxsal;
+-------+---------+--------+---------+
| ename | sal | deptno | maxsal |
+-------+---------+--------+---------+
| BLAKE | 2850.00 | 30 | 2850.00 |
| SCOTT | 3000.00 | 20 | 3000.00 |
| KING | 5000.00 | 10 | 5000.00 |
| FORD | 3000.00 | 20 | 3000.00 |
+-------+---------+--------+---------+
4 rows in set (0.00 sec)
2
3
4
5
6
7
8
9
10
显示每个部门的部门名、部门编号、所在地址和人员数量
mysql> select * from dept, (select deptno, count(ename) from emp group by deptno) temp where dept.deptno=temp.deptn
no;
+--------+------------+----------+--------+--------------+
| deptno | dname | loc | deptno | count(ename) |
+--------+------------+----------+--------+--------------+
| 10 | ACCOUNTING | NEW YORK | 10 | 3 |
| 20 | RESEARCH | DALLAS | 20 | 5 |
| 30 | SALES | CHICAGO | 30 | 6 |
+--------+------------+----------+--------+--------------+
3 rows in set (0.00 sec)
2
3
4
5
6
7
8
9
10
# 合并查询
合并查询,是指将多个查询结果进行合并,可使用的操作符有union和union all。
- union用于取得两个查询结果的并集,union会自动去掉结果集中的重复行。
- union all也用于取得两个查询结果的并集,但union all不会去掉结果集中的重复行。
- 待合并的两个查询结果的列的数量必须一致,否则无法合并。