复合查询(重点)
前面我们讲解的mysql表的查询都是对一张表进行查询,在实际开发中这远远不够。
1. 基本查询回顾
数据还是使用之前的雇员信息表
在标题7的位置!
mysql> select * from emp where sal > 500 or job = 'MANAGER';
+--------+--------+-----------+------+---------------------+---------+---------+--------+
| 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)
查询工资高于500或岗位为MANAGER的雇员,同时还要满足他们的姓名首字母为大写的J
# 可以用like模糊匹配的方法
mysql> select * from emp where (sal > 500 or job = 'MANAGER') and ename like 'J%';
+--------+-------+---------+------+---------------------+---------+------+--------+
| empno | ename | job | mgr | hiredate | sal | comm | deptno |
+--------+-------+---------+------+---------------------+---------+------+--------+
| 007566 | JONES | MANAGER | 7839 | 1981-04-02 00:00:00 | 2975.00 | NULL | 20 |
| 007900 | JAMES | CLERK | 7698 | 1981-12-03 00:00:00 | 950.00 | NULL | 30 |
+--------+-------+---------+------+---------------------+---------+------+--------+
2 rows in set (0.00 sec)
# 也可以用substring函数取字符
mysql> select * from emp where (sal>500 or job = "MANAGER") and substring(ename,1,1) = 'J';
+--------+-------+---------+------+---------------------+---------+------+--------+
| empno | ename | job | mgr | hiredate | sal | comm | deptno |
+--------+-------+---------+------+---------------------+---------+------+--------+
| 007566 | JONES | MANAGER | 7839 | 1981-04-02 00:00:00 | 2975.00 | NULL | 20 |
| 007900 | JAMES | CLERK | 7698 | 1981-12-03 00:00:00 | 950.00 | NULL | 30 |
+--------+-------+---------+------+---------------------+---------+------+--------+
2 rows in set (0.00 sec)
按照部门号升序而雇员的工资降序排序
mysql> select * from emp order by deptno asc, sal desc;
+--------+--------+-----------+------+---------------------+---------+---------+--------+
| empno | ename | job | mgr | hiredate | sal | comm | deptno |
+--------+--------+-----------+------+---------------------+---------+---------+--------+
| 007839 | KING | PRESIDENT | NULL | 1981-11-17 00:00:00 | 5000.00 | NULL | 10 |
| 007782 | CLARK | MANAGER | 7839 | 1981-06-09 00:00:00 | 2450.00 | NULL | 10 |
| 007934 | MILLER | CLERK | 7782 | 1982-01-23 00:00:00 | 1300.00 | NULL | 10 |
| 007788 | SCOTT | ANALYST | 7566 | 1987-04-19 00:00:00 | 3000.00 | NULL | 20 |
| 007902 | FORD | ANALYST | 7566 | 1981-12-03 00:00:00 | 3000.00 | NULL | 20 |
| 007566 | JONES | MANAGER | 7839 | 1981-04-02 00:00:00 | 2975.00 | NULL | 20 |
| 007876 | ADAMS | CLERK | 7788 | 1987-05-23 00:00:00 | 1100.00 | NULL | 20 |
| 007369 | SMITH | CLERK | 7902 | 1980-12-17 00:00:00 | 800.00 | NULL | 20 |
| 007698 | BLAKE | MANAGER | 7839 | 1981-05-01 00:00:00 | 2850.00 | NULL | 30 |
| 007499 | ALLEN | SALESMAN | 7698 | 1981-02-20 00:00:00 | 1600.00 | 300.00 | 30 |
| 007844 | TURNER | SALESMAN | 7698 | 1981-09-08 00:00:00 | 1500.00 | 0.00 | 30 |
| 007521 | WARD | SALESMAN | 7698 | 1981-02-22 00:00:00 | 1250.00 | 500.00 | 30 |
| 007654 | MARTIN | SALESMAN | 7698 | 1981-09-28 00:00:00 | 1250.00 | 1400.00 | 30 |
| 007900 | JAMES | CLERK | 7698 | 1981-12-03 00:00:00 | 950.00 | NULL | 30 |
+--------+--------+-----------+------+---------------------+---------+---------+--------+
14 rows in set (0.00 sec)
使用年薪进行降序排序
mysql> select (sal*12+comm) as 年薪 from emp order by 年薪;
+----------+
| 年薪 |
+----------+
| NULL |
| NULL |
| NULL |
| NULL |
| NULL |
| NULL |
| NULL |
| NULL |
| NULL |
| NULL |
| 15500.00 |
| 16400.00 |
| 18000.00 |
| 19500.00 |
+----------+
14 rows in set (0.00 sec)
这里年薪为NULL的原因是因为有些员工的奖金为NULL,
NULL值是不参与计算的,所以这里需要用到之前学到的函数ifnull()
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)
显示工资最高的员工的名字和工作岗位
mysql> select ename, job from emp where sal = (select max(sal) from emp );
+-------+-----------+
| ename | job |
+-------+-----------+
| KING | PRESIDENT |
+-------+-----------+
1 row in set (0.00 sec)
显示工资高于平均工资的员工信息
mysql> select * from emp where sal > (select avg(sal) from emp );
+--------+-------+-----------+------+---------------------+---------+------+--------+
| empno | ename | job | mgr | hiredate | sal | comm | deptno |
+--------+-------+-----------+------+---------------------+---------+------+--------+
| 007566 | JONES | MANAGER | 7839 | 1981-04-02 00:00:00 | 2975.00 | NULL | 20 |
| 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 |
| 007902 | FORD | ANALYST | 7566 | 1981-12-03 00:00:00 | 3000.00 | NULL | 20 |
+--------+-------+-----------+------+---------------------+---------+------+--------+
6 rows in set (0.00 sec)
显示每个部门的平均工资和最高工资
mysql> select deptno, avg(sal) 平均工资, max(sal) 最高工资 from emp group by deptno;
+--------+--------------+--------------+
| deptno | 平均工资 | 最高工资 |
+--------+--------------+--------------+
| 10 | 2916.666667 | 5000.00 |
| 20 | 2175.000000 | 3000.00 |
| 30 | 1566.666667 | 2850.00 |
+--------+--------------+--------------+
3 rows in set (0.00 sec)
mysql> select deptno, format(avg(sal), 2) , max(sal) from emp group by deptno;
+--------+---------------------+----------+
| deptno | format(avg(sal), 2) | max(sal) |
+--------+---------------------+----------+
| 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的部门号和它的平均工资
mysql> select deptno,format(avg(sal),2) 平均工资 from emp group by deptno having 平均工资 <2000;
+--------+--------------+
| deptno | 平均工资 |
+--------+--------------+
| 10 | 2,916.67 |
| 20 | 2,175.00 |
| 30 | 1,566.67 |
+--------+--------------+
3 rows in set (0.00 sec)
显示每种岗位的雇员总数,平均工资
mysql> select job, count(*) ,format(avg(sal),2) 平均工资 from emp group by job;
+-----------+----------+--------------+
| job | count(*) | 平均工资 |
+-----------+----------+--------------+
| 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)
2. 多表查询
实际开发中往往数据来自不同的表,所以需要多表查询。
本节我们用一个简单的公司管理系统,有三张表EMP,DEPT,SALGRADE来演示如何进行多表查询。
案例:
显示雇员名、雇员工资以及所在部门的名字因为上面的数据来自EMP和DEPT表,因此要联合查询
其实我们只要emp表中的deptno = dept表中的deptno字段的记录
mysql> select emp.ename, emp.sal, dept.dname, dept.deptno from emp,dept where emp.deptno = dept.deptno;
+--------+---------+------------+--------+
| ename | sal | dname | deptno |
+--------+---------+------------+--------+
| SMITH | 800.00 | RESEARCH | 20 |
| ALLEN | 1600.00 | SALES | 30 |
| WARD | 1250.00 | SALES | 30 |
| JONES | 2975.00 | RESEARCH | 20 |
| MARTIN | 1250.00 | SALES | 30 |
| BLAKE | 2850.00 | SALES | 30 |
| CLARK | 2450.00 | ACCOUNTING | 10 |
| SCOTT | 3000.00 | RESEARCH | 20 |
| KING | 5000.00 | ACCOUNTING | 10 |
| TURNER | 1500.00 | SALES | 30 |
| ADAMS | 1100.00 | RESEARCH | 20 |
| JAMES | 950.00 | SALES | 30 |
| FORD | 3000.00 | RESEARCH | 20 |
| MILLER | 1300.00 | ACCOUNTING | 10 |
+--------+---------+------------+--------+
14 rows in set (0.00 sec)
显示部门号为10的部门名,员工名和工资
mysql> select dname,ename,sal from emp,dept where emp.deptno = dept.deptno and emp.deptno = '10';
+------------+--------+---------+
| dname | ename | sal |
+------------+--------+---------+
| ACCOUNTING | CLARK | 2450.00 |
| ACCOUNTING | KING | 5000.00 |
| ACCOUNTING | MILLER | 1300.00 |
+------------+--------+---------+
3 rows in set (0.00 sec)
显示各个员工的姓名,工资,及工资级别
mysql> select emp.ename, emp.sal, salgrade.grade, salgrade.losal,salgrade.hisal from emp,salgrade where emp.sal between salgrade.losal and salgrade.hisal;
+--------+---------+-------+-------+-------+
| ename | sal | grade | losal | hisal |
+--------+---------+-------+-------+-------+
| SMITH | 800.00 | 1 | 700 | 1200 |
| ALLEN | 1600.00 | 3 | 1401 | 2000 |
| WARD | 1250.00 | 2 | 1201 | 1400 |
| JONES | 2975.00 | 4 | 2001 | 3000 |
| MARTIN | 1250.00 | 2 | 1201 | 1400 |
| BLAKE | 2850.00 | 4 | 2001 | 3000 |
| CLARK | 2450.00 | 4 | 2001 | 3000 |
| SCOTT | 3000.00 | 4 | 2001 | 3000 |
| KING | 5000.00 | 5 | 3001 | 9999 |
| TURNER | 1500.00 | 3 | 1401 | 2000 |
| ADAMS | 1100.00 | 1 | 700 | 1200 |
| JAMES | 950.00 | 1 | 700 | 1200 |
| FORD | 3000.00 | 4 | 2001 | 3000 |
| MILLER | 1300.00 | 2 | 1201 | 1400 |
+--------+---------+-------+-------+-------+
14 rows in set (0.00 sec)
3. 自连接
自连接是指在同一张表连接查询
案例:
使用的子查询:
显示员工FORD的上级领导的编号和姓名(mgr是员工领导的编号--empno)
mysql> select * from emp where empno = (select mgr from emp where ename = 'FORD');
+--------+-------+---------+------+---------------------+---------+------+--------+
| empno | ename | job | mgr | hiredate | sal | comm | deptno |
+--------+-------+---------+------+---------------------+---------+------+--------+
| 007566 | JONES | MANAGER | 7839 | 1981-04-02 00:00:00 | 2975.00 | NULL | 20 |
+--------+-------+---------+------+---------------------+---------+------+--------+
1 row in set (0.00 sec)
使用多表查询(自查询)
-- 使用到表的别名
--from emp leader, emp worker,给自己的表起别名,因为要先做笛卡尔积,所以别名可以先识别
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)