mysql>select ename, sal from emp where sal > (selectavg(sal) from emp); # 单行单列 +-------+---------+ | ename | sal | +-------+---------+ | JONES |2975.00| | BLAKE |2850.00| | CLARK |2450.00| | SCOTT |3000.00| | KING |5000.00| | FORD |3000.00| +-------+---------+
2. 多行子查询
子查询返回 多行 1 列,用 IN / ANY / ALL(IN 最常用,ANY 和 ALL 用得少)
# 工资等于 SALES 部门任意一个人工资的员工 mysql>select ename,sal,deptno from emp where sal in (select sal from emp where deptno=30); # 多行 +--------+---------+--------+ | ename | sal | deptno | +--------+---------+--------+ | ALLEN |1600.00|30| | WARD |1250.00|30| | MARTIN |1250.00|30| | BLAKE |2850.00|30| | TURNER |1500.00|30| | JAMES |950.00|30| +--------+---------+--------+
# 工资 > SALES 部门任意工资的员工 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| +--------+---------+--------+
# 工资 > SALES 部门所有工资的员工(比最高的还高) 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| +-------+---------+--------+
3. 多列子查询
子查询查出来几列(多行多列),外层 WHERE 就得用几列包成一组去比。把列名用括号括起来 (col1, col2),后面接 IN 或者 = 就行。 比如里面查两列,外面就得拿两列一起比,用括号把列名括起来 (job, deptno),后面写 IN 或 =。
意思是:必须 job 和 deptno 这两列的组合,跟子查询查出来的组合一模一样,才算匹配。 就像找坐标 (x, y),必须 x 和 y 都对上才行,光 x 对上没用。
1 2 3 4 5 6 7 8 9 10 11 12 13
# 找出和 CLARK 同部门、同职位的员工 mysql>select ename, job, deptno from emp ->where (deptno, job) in (select deptno, job from emp where ename='CLARK'); +-------+---------+--------+ | ename | job | deptno | +-------+---------+--------+ | CLARK | MANAGER |10| +-------+---------+--------+ 1rowinset (0.00 sec)
# 注意:顺序必须死一致:第一个对第一个,第二个对第二个! mysql>select ename, job, deptno from emp where (deptno, job) in (select job, deptno from emp where ename='CLARK'); Emptyset, 15 warnings (0.00 sec)
# 每个部门平均工资,并和部门表连起来 select d.dname, t.avg_sal from dept d # 括号里是个子查询,先算出每个部门的平均工资,当成一张临时表,别名叫 t join (select deptno, avg(sal) as avg_sal from emp groupby deptno) t # 拿着部门表 d 和 临时表 t 连起来,连接条件就是部门号相等 on d.deptno = t.deptno; +------------+-------------+ | dname | avg_sal | +------------+-------------+ | ACCOUNTING |2916.666667| | RESEARCH |2175.000000| | SALES |1566.666667| +------------+-------------+
# 显示每个部门工资最高的员工的姓名、工资、部门和部门的最高工资 select e.ename 姓名, e.sal 工资, d.dname 部门, e.sal 部门最高工资 from emp e join dept d on e.deptno = d.deptno # 核心是后面这个子查询:每扫描一行员工,都去算一下他所在部门的最高工资 # 如果当前员工工资等于部门最高工资,那就留下来 where e.sal = (selectmax(sal) from emp where deptno = e.deptno); +--------+---------+------------+--------------------+ | 姓名 | 工资 | 部门 | 部门最高工资 | +--------+---------+------------+--------------------+ | BLAKE |2850.00| SALES |2850.00| | SCOTT |3000.00| RESEARCH |3000.00| | KING |5000.00| ACCOUNTING |5000.00| | FORD |3000.00| RESEARCH |3000.00| +--------+---------+------------+--------------------+
# 显示每个部门的部门名、部门编号、所在地址和人员数量 select d.dname 部门名, d.deptno 部门编号, d.loc 地址, count(e.empno) 人员数量 from dept d # 用左连接,保证就算没人的部门(比如 40 号)也能查出来,人数显示 0 leftjoin emp e on d.deptno = e.deptno # 分组后才能用 count 统计每个组的人数,非聚合列都要写在这里 groupby d.deptno, d.dname, d.loc; +------------+--------------+----------+--------------+ | 部门名 | 部门编号 | 地址 | 人员数量 | +------------+--------------+----------+--------------+ | ACCOUNTING |10|NEW YORK |3| | RESEARCH |20| DALLAS |5| | SALES |30| CHICAGO |6| | OPERATIONS |40| BOSTON |0| +------------+--------------+----------+--------------+
mysql>select ename name from emp unionselect dname from dept; +------------+ | name | +------------+ | SMITH | | ALLEN | | WARD | | JONES | | MARTIN | | BLAKE | | CLARK | | SCOTT | | KING | | TURNER | | ADAMS | | JAMES | | FORD | | MILLER | | ACCOUNTING | | RESEARCH | | SALES | | OPERATIONS | +------------+
合并显示所有员工的职位(job)和所有部门地点(loc),去重
1 2 3 4 5 6 7 8 9 10 11 12 13 14
mysql>select job jobAndLoc from emp unionselect loc from dept; +-----------+ | jobAndLoc | +-----------+ | CLERK | | SALESMAN | | MANAGER | | ANALYST | | PRESIDENT | |NEW YORK | | DALLAS | | CHICAGO | | BOSTON | +-----------+