Mysql子查询

一、用到的三个表

员工表:
+-------+--------+-----------+------+------------+---------+---------+--------+
| EMPNO | ENAME  | JOB       | MGR  | HIREDATE   | SAL     | COMM    | DEPTNO |
+-------+--------+-----------+------+------------+---------+---------+--------+
|  7369 | SMITH  | CLERK     | 7902 | 1980-12-17 |  800.00 |    NULL |     20 |
|  7499 | ALLEN  | SALESMAN  | 7698 | 1981-02-20 | 1600.00 |  300.00 |     30 |
|  7521 | WARD   | SALESMAN  | 7698 | 1981-02-22 | 1250.00 |  500.00 |     30 |
|  7566 | JONES  | MANAGER   | 7839 | 1981-04-02 | 2975.00 |    NULL |     20 |
|  7654 | MARTIN | SALESMAN  | 7698 | 1981-09-28 | 1250.00 | 1400.00 |     30 |
|  7698 | BLAKE  | MANAGER   | 7839 | 1981-05-01 | 2850.00 |    NULL |     30 |
|  7782 | CLARK  | MANAGER   | 7839 | 1981-06-09 | 2450.00 |    NULL |     10 |
|  7788 | SCOTT  | ANALYST   | 7566 | 1987-04-19 | 3000.00 |    NULL |     20 |
|  7839 | KING   | PRESIDENT | NULL | 1981-11-17 | 5000.00 |    NULL |     10 |
|  7844 | TURNER | SALESMAN  | 7698 | 1981-09-08 | 1500.00 |    0.00 |     30 |
|  7876 | ADAMS  | CLERK     | 7788 | 1987-05-23 | 1100.00 |    NULL |     20 |
|  7900 | JAMES  | CLERK     | 7698 | 1981-12-03 |  950.00 |    NULL |     30 |
|  7902 | FORD   | ANALYST   | 7566 | 1981-12-03 | 3000.00 |    NULL |     20 |
|  7934 | MILLER | CLERK     | 7782 | 1982-01-23 | 1300.00 |    NULL |     10 |
+-------+--------+-----------+------+------------+---------+---------+--------+
部门表:
+--------+------------+----------+
| DEPTNO | DNAME      | LOC      |
+--------+------------+----------+
|     10 | ACCOUNTING | NEW YORK |
|     20 | RESEARCH   | DALLAS   |
|     30 | SALES      | CHICAGO  |
|     40 | OPERATIONS | BOSTON   |
+--------+------------+----------+
薪资等级表:
+-------+-------+-------+
| GRADE | LOSAL | HISAL |
+-------+-------+-------+
|     1 |   700 |  1200 |
|     2 |  1201 |  1400 |
|     3 |  1401 |  2000 |
|     4 |  2001 |  3000 |
|     5 |  3001 |  9999 |
+-------+-------+-------+

二、子查询

嵌套在其他查查询中的查询叫做子查询。

问题描述:

假设现在我们要查询所有在 NEW YORK 和 CHICAGO工作的员工,但是

员工的工作地址信息存储在部门表中,员工具体姓名存在员工表中。

1、先查找 NEW YORK 和 CHICAGO工作的员工的部门编号

mysql> select deptno from dept where loc in ('NEW YORK','CHICAGO');
+--------+
| deptno |
+--------+
|     10 |
|     30 |
+--------+
2 rows in set (0.00 sec)

2、然后查询部门编号为10和30的员工

mysql> select ename ,deptno from emp where deptno in(10,30);
+--------+--------+
| ename  | deptno |
+--------+--------+
| ALLEN  |     30 |
| WARD   |     30 |
| MARTIN |     30 |
| BLAKE  |     30 |
| CLARK  |     10 |
| KING   |     10 |
| TURNER |     30 |
| JAMES  |     30 |
| MILLER |     10 |
+--------+--------+
9 rows in set (0.00 sec)

3、使用子查询合并两个查询语句

mysql> select ename ,deptno from emp where deptno in (select deptno from dept where loc in ('NEW YORK','CHICAGO'));
+--------+--------+
| ename  | deptno |
+--------+--------+
| ALLEN  |     30 |
| WARD   |     30 |
| MARTIN |     30 |
| BLAKE  |     30 |
| CLARK  |     10 |
| KING   |     10 |
| TURNER |     30 |
| JAMES  |     30 |
| MILLER |     10 |
+--------+--------+
9 rows in set (0.00 sec)

分析:

select 语句的执行是从内朝外的,上面的SQL语句其实执行两个操作,先部门表中找到了 new york 和 chicago 员工的部门编号,查询到的结果以IN操作符要求的逗号分隔的形式传给了外部查询的where子句,然后外部查询在正常执行,所以我们看到两种方案查询到的结果是相同的。

注意事项

  • 在where子句中使用子查询,应该保证select语句中有于where子句中相同数目的列。通常子查询将会返回单个列然后于单个列进行匹配,如果有需要也可以使用多个列。
  • 嵌套过多的子查询可能会严重影响查询的性能

三、格式化SQL

为了是包含子查询的SELECT语句阅读和调试更容易,把子查询做适当的分解多行和缩进可以简化子查询的使用。

示例:

mysql> select ename ,deptno 
	   from emp 
	   where deptno in (select deptno 
	   					from dept 
	   					where loc in ('NEW YORK','CHICAGO'));
+--------+--------+
| ename  | deptno |
+--------+--------+
| ALLEN  |     30 |
| WARD   |     30 |
| MARTIN |     30 |
| BLAKE  |     30 |
| CLARK  |     10 |
| KING   |     10 |
| TURNER |     30 |
| JAMES  |     30 |
| MILLER |     10 |
+--------+--------+
9 rows in set (0.00 sec)

四、作为计算字段使用子查询

问题:

统计员工表中每个部门的人数。

  1. 先检索部门列表
  2. 对于每个部门,统计其在员工表中出现的次数

例如:我们统计部门号为30的人数

mysql> select count(*) from emp where deptno = 30;
+----------+
| count(*) |
+----------+
|        6 |
+----------+
1 row in set (0.00 sec)

为了将每个部门执行count(*)计算,应该将count(*)作为一个子查询。

mysql> select deptno,dname ,(select count(*) from emp where deptno = dept.deptno) as '人数' 
	   from dept 
	   order by (select count(*) 
	             from emp 
	             where deptno = dept.deptno) desc;
+--------+------------+--------+
| deptno | dname      | 人数   |
+--------+------------+--------+
|     30 | SALES      |      6 |
|     20 | RESEARCH   |      5 |
|     10 | ACCOUNTING |      3 |
|     40 | OPERATIONS |      0 |
+--------+------------+--------+
4 rows in set (0.00 sec)

分析

上面的select语句对于每个部门都返回三列,deptno,dname和人数。人数是一个可计算的字段,它是由圆括号括起来的子查询建立的,这个子查询对检索出爱的灭个部门号都执行一次,这个例子中被执行了四次,因为一共就只有四个部门,每次检索到一个部门,他都会去员工表中统计一次人数。

五、相关子查询

涉及外部查询的子查询叫做相关子查询

当列名存在多义性例如上面的emp.deptno = dept.deptno,这时候就必须使用完全限定名(表明.列名)

六、用法总结

需要预先直到一个数据或者一堆数据作为某些查询的过滤条件或者总结字段时候我们先使用一个子查询

1、需要一个特定的值,但是这个值不能直接得到,需要进一步查询,子查询结果返回单行单列。

例如:查询所有薪资比MILLER高的员工

mysql> select ename,sal from emp where sal > all(select sal from emp where  ename
= 'miller');
+--------+---------+
| ename  | sal     |
+--------+---------+
| ALLEN  | 1600.00 |
| JONES  | 2975.00 |
| BLAKE  | 2850.00 |
| CLARK  | 2450.00 |
| SCOTT  | 3000.00 |
| KING   | 5000.00 |
| TURNER | 1500.00 |
| FORD   | 3000.00 |
+--------+---------+
8 rows in set (0.00 sec)

2、需要一堆数据,这堆数据都被作为过滤的条件,子查询结果返回单行多列

mysql> select ename ,deptno from emp where deptno in (select deptno from dept where loc in ('NEW YORK','CHICAGO'));
+--------+--------+
| ename  | deptno |
+--------+--------+
| ALLEN  |     30 |
| WARD   |     30 |
| MARTIN |     30 |
| BLAKE  |     30 |
| CLARK  |     10 |
| KING   |     10 |
| TURNER |     30 |
| JAMES  |     30 |
| MILLER |     10 |
+--------+--------+
9 rows in set (0.00 sec)

3、需要多对信息(多列多行)作为过滤条件,子查询结果返回多列多行

mysql> select ename , sal , job ,deptno 
       from emp 
       where (deptno , sal ) in (select deptno , max(sal) 
                                 from emp 
                                 group by deptno);
+-------+---------+-----------+--------+
| ename | sal     | job       | deptno |
+-------+---------+-----------+--------+
| BLAKE | 2850.00 | MANAGER   |     30 |
| SCOTT | 3000.00 | ANALYST   |     20 |
| KING  | 5000.00 | PRESIDENT |     10 |
| FORD  | 3000.00 | ANALYST   |     20 |
+-------+---------+-----------+--------+
4 rows in set (0.00 sec)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值