MYSQL学习笔记之子查询

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MYSQL学习笔记之子查询相关的知识,希望对你有一定的参考价值。

MYSQL学习笔记之子查询_子查询

(一)基本介绍

         select语句中可以嵌套select语句,被嵌套的select语句被称为子查询。

(二)应用场景

     select ...(select )  from ...(select )  where ...(select)..

(三)具体实例

where

实例:找出比最低工资高的员工姓名和工资??

mysql> select ename,sal from emp where sal>min(sal);
ERROR 1111 (HY000): Invalid use of group function
#错误原因:where子句中不能直接使用分组函数
#正确方法如下
#第一步:找出emp表中sal的最小值
mysql> select min(sal) from emp;
+----------+
| min(sal) |
+----------+
| 800.00 |
+----------+
1 row in set (0.00 sec)
#第二步:根据最小值来进行选择和输出符合条件的员工名字和薪水
mysql> select ename,sal from emp where sal>800;
+--------+---------+
| ename | sal |
+--------+---------+
| ALLEN | 1600.00 |
| WARD | 1250.00 |
| JONES | 2975.00 |
| MARTIN | 1250.00 |
| BLAKE | 2850.00 |
| CLARK | 2450.00 |
| SCOTT | 3000.00 |
| KING | 5000.00 |
| TURNER | 1500.00 |
| ADAMS | 1100.00 |
| JAMES | 950.00 |
| FORD | 3000.00 |
| MILLER | 1300.00 |
+--------+---------+
13 rows in set (0.00 sec)

#方法二:通过子查询实现(先执行‘ 子查询 ’,然后再执行‘ 外查询 ’)
mysql> select ename,sal from emp where sal>(select min(sal) from emp);
+--------+---------+
| ename | sal |
+--------+---------+
| ALLEN | 1600.00 |
| WARD | 1250.00 |
| JONES | 2975.00 |
| MARTIN | 1250.00 |
| BLAKE | 2850.00 |
| CLARK | 2450.00 |
| SCOTT | 3000.00 |
| KING | 5000.00 |
| TURNER | 1500.00 |
| ADAMS | 1100.00 |
| JAMES | 950.00 |
| FORD | 3000.00 |
| MILLER | 1300.00 |
+--------+---------+
13 rows in set (0.00 sec)

mysql>

from

实例:找出每个岗位的平均工资的薪资等级

分析:

第一步:根据岗位进行分组,并求出每个分组中的薪水平均值

              select job,avg(sal) from emp group by job;

第二步:将上表(假设为 s)和 薪资等级表(s)进行连接,可得目标结果

            select

                  t.* ,s.grade

            from

                  ( select job,avg(sal) as avgsal from emp group by job) t

           join

                 salgrade s

           on

               t.avgsal between s.losal and s.hisal;

#未起别名
mysql> select job,avg(sal) from emp group by job;
+-----------+-------------+
| job | avg(sal) |
+-----------+-------------+
| CLERK | 1037.500000 |
| SALESMAN | 1400.000000 |
| MANAGER | 2758.333333 |
| ANALYST | 3000.000000 |
| PRESIDENT | 5000.000000 |
+-----------+-------------+
5 rows in set (0.00 sec)

#起别名
mysql> select job,avg(sal) as avgsal from emp group by job;
+-----------+-------------+
| job | avgsal |
+-----------+-------------+
| CLERK | 1037.500000 |
| SALESMAN | 1400.000000 |
| MANAGER | 2758.333333 |
| ANALYST | 3000.000000 |
| PRESIDENT | 5000.000000 |
+-----------+-------------+
5 rows in set (0.00 sec)

mysql> select t.* ,s.grade from ( select job,avg(sal) as avgsal from emp group by job) t join salgrade s on t.avgsal between s.losal and s.hisal;
+-----------+-------------+-------+
| job | avgsal | grade |
+-----------+-------------+-------+
| CLERK | 1037.500000 | 1 |
| SALESMAN | 1400.000000 | 2 |
| MANAGER | 2758.333333 | 4 |
| ANALYST | 3000.000000 | 4 |
| PRESIDENT | 5000.000000 | 5 |
+-----------+-------------+-------+
5 rows in set (0.00 sec)

注意:from后面的子查询,可以将子查询的查询结果当做一张临时表。(技巧)

select

案例:找出每个员工的部门名称,要求显示员工名、部门名??

mysql> select e.ename,(select d.dname from dept d where e.deptno = d.deptno) as dname from emp e;
+--------+------------+
| ename | dname |
+--------+------------+
| SMITH | RESEARCH |
| ALLEN | SALES |
| WARD | SALES |
| JONES | RESEARCH |
| MARTIN | SALES |
| BLAKE | SALES |
| CLARK | ACCOUNTING |
| SCOTT | RESEARCH |
| KING | ACCOUNTING |
| TURNER | SALES |
| ADAMS | RESEARCH |
| JAMES | SALES |
| FORD | RESEARCH |
| MILLER | ACCOUNTING |
+--------+------------+
14 rows in set (0.00 sec)

错误情况:

mysql> select e.ename,(select dname from dept) as dname from emp e;
ERROR 1242 (21000): Subquery returns more than 1 row

#说明:dept中的记录个数是四个,并不是一个,所以说在匹配时候会出现错误
mysql> select dname from dept;
+------------+
| dname |
+------------+
| ACCOUNTING |
| RESEARCH |
| SALES |
| OPERATIONS |
+------------+
4 rows in set (0.00 sec)

说明:select后面的子查询只能返回一条结果,如果多于一条就会报错

Union

功能:查询并合并结果集

使用案例:

查询工作岗位是MANAGER和SALESMAN的员工

#方式一
mysql> select ename,job from emp where job=MANAGER or job =SALESMAN;
+--------+----------+
| ename | job |
+--------+----------+
| ALLEN | SALESMAN |
| WARD | SALESMAN |
| JONES | MANAGER |
| MARTIN | SALESMAN |
| BLAKE | MANAGER |
| CLARK | MANAGER |
| TURNER | SALESMAN |
+--------+----------+
7 rows in set (0.00 sec)

#方式二
mysql> select ename ,job from emp where job = MANAGER union select ename,job from emp where job =SALESMAN;
+--------+----------+
| ename | job |
+--------+----------+
| JONES | MANAGER |
| BLAKE | MANAGER |
| CLARK | MANAGER |
| ALLEN | SALESMAN |
| WARD | SALESMAN |
| MARTIN | SALESMAN |
| TURNER | SALESMAN |
+--------+----------+
7 rows in set (0.00 sec)

#方式三
mysql> select ename,job from emp where job in (MANAGER,SALESMAN);
+--------+----------+
| ename | job |
+--------+----------+
| ALLEN | SALESMAN |
| WARD | SALESMAN |
| JONES | MANAGER |
| MARTIN | SALESMAN |
| BLAKE | MANAGER |
| CLARK | MANAGER |
| TURNER | SALESMAN |
+--------+----------+
7 rows in set (0.00 sec)

总结:

        union的效率更高一点,对于表的连接来说,每连接一次新表,则匹配的次数满足笛卡尔积,但是union是可以减少匹配次数的,并且在减少匹配次数的同时,还可以完成两个结果集的拼接。

说明:

表a:10条记录

表b:10条记录

表c:10条记录

要求:合并三个表中数据

方式(一)普通的连接:

表a与表b连接:  匹配次数     10*10=100(次)

表a与表c连接:  匹配次数     10*10=100(次)

总匹配次数为: 10 * 10 * 10=1000(次)

方式(二)union连接(乘法变成了加法):

     表a与表b连接:  匹配次数     10*10=100(次)

     表a与表c连接:  匹配次数     10*10=100(次)

    总匹配次数为:100+100=200(次)


union使用说明:

满足条件:

       union在进行结果集合并的时候,要求两个结果集的列数(和数据类型)均相同。


Limit

用法如下:

完整用法:limit startIndex ,length;(startIndex是起始下标    length是长度)

缺省用法: limit 5(这里指的是取前五个记录)

功能:

将查询结果的一部分取出来(通常使用在分页查询中)

为什么要分页呢?

    分页可以提高用户的体验,如果每一次全部都查出来,用户体验就会降低。

具体实例:

  按照薪资降序排列,取出排名在前5名的员工?

mysql> select ename,sal from emp order by sal desc limit 5;
+-------+---------+
| ename | sal |
+-------+---------+
| KING | 5000.00 |
| SCOTT | 3000.00 |
| FORD | 3000.00 |
| JONES | 2975.00 |
| BLAKE | 2850.00 |
+-------+---------+
5 rows in set (0.00 sec)

注意:mysql中limit是在order by之后使用的!!!

取出工资排名在[3,5]名的员工?

#按照工资从高到低的顺序进行排序展示
mysql> select ename,sal from emp order by sal desc ;
+--------+---------+
| ename | sal |
+--------+---------+
| KING | 5000.00 |
| SCOTT | 3000.00 |
| FORD | 3000.00 |
| JONES | 2975.00 |
| BLAKE | 2850.00 |
| CLARK | 2450.00 |
| ALLEN | 1600.00 |
| TURNER | 1500.00 |
| MILLER | 1300.00 |
| WARD | 1250.00 |
| MARTIN | 1250.00 |
| ADAMS | 1100.00 |
| JAMES | 950.00 |
| SMITH | 800.00 |
+--------+---------+
14 rows in set (0.00 sec)


#选出从工资排名表中下标从2(第三个员工)开始连续三个员工的工资
mysql> select ename,sal from emp order by sal desc limit 2,3;
+-------+---------+
| ename | sal |
+-------+---------+
| FORD | 3000.00 |
| JONES | 2975.00 |
| BLAKE | 2850.00 |
+-------+---------+
3 rows in set (0.00 sec)

分页:

如果每页显示三条记录

第1页: limit  0,3     [0,1,2]

第2页: limit  3,3     [3,4,5]

第3页: limit  6,3     [6,7,8]

第4页:limit   9,3     [9,10,11]

每页显示pageSize条记录

第pageNo页: limit   (PageNo -1) * pageSize ,pageSize


DQL语句大总结:

select...from...where...group by...having...order by...limit...

执行顺序:

①    from

②    where

③    group by

④    having 

⑤    select

⑥    order by

⑦    limit...

以上是关于MYSQL学习笔记之子查询的主要内容,如果未能解决你的问题,请参考以下文章

MySQL数据处理(数据的查询之子查询复查询)

MySQL基础之子查询

MySQL 之子查询

mysql之子查询作业

mysql多表查询之子语句查询

MySql数据库之子查询和高级应用