MySQL中的子查询

  是在MySQL中经常使用到的一个操作,不仅仅是用在DQL语句中,在DDL语句、DML语句中也都会常用到子查询。

子查询的定义:

  子查询是将一个查询语句嵌套在另一个查询语句中;

  在特定情况下,一个查询语句的条件需要另一个查询语句来获取,内层查询(inner query)语句的查询结果,可以为外层查询(outer query)语句提供查询条件。

特点(规范):

  ①子查询必须放在小括号中

  ②子查询一般放在比较操作符的右边,以增强代码可读性

  ③子查询(小括号里的内容)可出现在几乎所有的SELECT子句中(如:SELECT子句、FROM子句、WHERE子句、ORDER BY子句、HAVING子句……)

(相关、不相关)子查询分类:

  ①标量子查询(scalar subquery):返回1行1列一个值

  ②行子查询(row subquery):返回的结果集是 1 行 N 列

  ③列子查询(column subquery):返回的结果集是 N 行 1列

  ④表子查询(table subquery):返回的结果集是 N 行 N 列

可以使用的操作符:= > < >= <= <> ANY IN SOME ALL EXISTS

注意:一个子查询会返回一个标量(就一个值)、一个行、一个列或一个表,这些子查询称之为标量、行、列和表子查询

  1、如果子查询返回一个标量值(就一个值),那么外部查询就可以使用:=、>、<、>=、<=和<>符号进行比较判断;

  2、如果子查询返回的不是一个标量值,而外部查询使用了比较符和子查询的结果进行了比较,那么就会抛出异常。

环境搭建:employee雇员表、department部门表、TENNIS数据库

mysql> select * from department;
+------+-----------+--------------+---------------------+
| d_id | d_name | function | address |
+------+-----------+--------------+---------------------+
| 1001 | 科技部 | 研发产品 | 3号楼5层 |
| 1002 | 生产部 | 生产产品 | 5号楼1层 |
| 1003 | 销售部 | 策划销售 | 1号楼销售大厅 |
+------+-----------+--------------+---------------------+
3 rows in set (0.02 sec) mysql> select * from employee;
+------+------+--------+------+------+--------------------+
| num | d_id | name | age | sex | homeaddr |
+------+------+--------+------+------+--------------------+
| 1 | 1001 | 张三 | 26 | 男 | 北京市海淀区 |
| 2 | 1001 | 李四 | 24 | 女 | 上海市黄浦区 |
| 3 | 1002 | 王五 | 25 | 男 | 江西省赣州市 |
| 4 | 1004 | Aric | 15 | 男 | England |
+------+------+--------+------+------+--------------------+
4 rows in set (0.00 sec)
mysql> use TENNIS
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A Database changed
mysql> show tables;
+-------------------+
| Tables_in_TENNIS |
+-------------------+
| COMMITTEE_MEMBERS |
| MATCHES |
| PENALTIES |
| PLAYERS |
| TEAMS |
+-------------------+
5 rows in set (0.00 sec)

一、不相关子查询

  不相关,主查询和子查询是不相关的关系。也就是意味着在子查询中没有使用到外部查询的表中的任何列。

  先执行子查询,然后执行外部查询

1、标量子查询(scalar subquery):返回1行1列一个值

  因为是标量子查询,结果是一个值,所以可用来进行算数运算。

  可以使用 = > < >= <= <> 操作符对子查询的结果进行比较:

mysql> select num,name
-> from employee
-> where d_id=(
->   select d_id
->   from department
->   where d_name='科技部');
+------+--------+
| num | name |
+------+--------+
| 1 | 张三 |
| 2 | 李四 |
+------+--------+
mysql> select num,name
-> from employee
-> where d_id=(
->   select d_id
->   from department
->   where d_name='财务部');
Empty set (0.00 sec)
注意:如果子查询返回空值,可能导致外部查询的where条件也为空,从而外部查询的结果集为空。
mysql> SELECT  playerno,town,sex
-> FROM PLAYERS
-> WHERE (town,sex) = ((SELECT town FROM PLAYERS WHERE playerno=7),
-> (SELECT sex FROM PLAYERS WHERE playerno=44));
+----------+-----------+-----+
| playerno | town | sex |
+----------+-----------+-----+
| 2 | Stratford | M |
| 6 | Stratford | M |
| 7 | Stratford | M |
| 39 | Stratford | M |
| 57 | Stratford | M |
| 83 | Stratford | M |
| 100 | Stratford | M |
+----------+-----------+-----+
7 rows in set (0.01 sec)
注意: (列,列,…)叫做行表达式,比较时是比较列的组合。

2、行子查询(row subquery):返回的结果集是 1 行 N 列

  使用行表达式进行比较,可以使用 = > < >= <= <> in操作符

mysql> select d_id from department;
+------+
| d_id |
+------+
| 1001 |
| 1002 |
| 1003 |
+------+ mysql> select * from employee
-> where d_id in
->   (select d_id from department);
+------+------+--------+------+------+--------------------+
| num | d_id | name | age | sex | homeaddr |
+------+------+--------+------+------+--------------------+
| 1 | 1001 | 张三 | 26 | 男 | 北京市海淀区 |
| 2 | 1001 | 李四 | 24 | 女 | 上海市黄浦区 |
| 3 | 1002 | 王五 | 25 | 男 | 江西省赣州市 |
+------+------+--------+------+------+--------------------+

解析:此处首先查询出department表中所有d_id字段的信息,并将结果作为条件,接着查询employee表中以d_id为条件的所有字段信息;NOT IN的效果与上面刚好相反。

3、列子查询(column subquery):返回的结果集是 N 行 1列

  必须使用 IN、ANY 和 ALL 操作符对子查询返回的结果进行比较

注意:ANY 和 ALL 操作符不能单独使用,其前面必须加上单行比较操作符= > < >= <= <>

1)带ANY关键字的子查询:ANY关键字表示满足其中任一条件

mysql> select * from employee
-> where d_id !=any
->   (select d_id from department);
+------+------+--------+------+------+--------------------+
| num | d_id | name | age | sex | homeaddr |
+------+------+--------+------+------+--------------------+
| 1 | 1001 | 张三 | 26 | 男 | 北京市海淀区 |
| 2 | 1001 | 李四 | 24 | 女 | 上海市黄浦区 |
| 3 | 1002 | 王五 | 25 | 男 | 江西省赣州市 |
| 4 | 1004 | Aric | 15 | 男 | England |
+------+------+--------+------+------+--------------------+

2)带ALL关键字的子查询:ALL关键字表示满足其中所有条件

mysql> select * from employee
-> where d_id >=all
->   (select d_id from department);
+------+------+------+------+------+----------+
| num | d_id | name | age | sex | homeaddr |
+------+------+------+------+------+----------+
| 4 | 1004 | Aric | 15 | 男 | England |
+------+------+------+------+------+----------+

注意:如果子查询的结果集中有null值,使用>ALL 和not in操作符时,必须去掉子查询结果集中的null值,否则查询结果错误

mysql> select * from department
-> where d_id >all #>all背后执行and操作
->   (select d_id from employee);
Empty set (0.01 sec)
结果为空:子查询的结果集中包含null值(子查询结果集中没有主查询里的1004行,则为空)。

4、表子查询(table subquery):返回的结果集是 N 行 N 列

  必须使用 IN、ANY 和 ALL 操作符对子查询返回的结果进行比较

示例:在committee_members表中,得到任职日期和卸任日期与具有Secretary职位的一行相同的所有行

mysql> select *
-> from COMMITTEE_MEMBERS
-> where (begin_date,end_date) in
-> (
-> select begin_date,end_date
-> from COMMITTEE_MEMBERS
-> where position='Secretary'
-> );
+----------+------------+------------+-----------+
| PLAYERNO | BEGIN_DATE | END_DATE | POSITION |
+----------+------------+------------+-----------+
| 6 | 1990-01-01 | 1990-12-31 | Secretary |
| 8 | 1990-01-01 | 1990-12-31 | Treasurer |
| 8 | 1991-01-01 | 1991-12-31 | Secretary |
| 27 | 1990-01-01 | 1990-12-31 | Member |
| 27 | 1991-01-01 | 1991-12-31 | Treasurer |
| 57 | 1992-01-01 | 1992-12-31 | Secretary |
| 112 | 1992-01-01 | 1992-12-31 | Member |
+----------+------------+------------+-----------+
7 rows in set (0.05 sec)

二、相关子查询(correlated subquery)

  在子查询中使用到了外部查询的表中的任何列。

  先执行外部查询,然后执行子查询

相关子查询的执行步骤:

  ①先执行外部查询,得到的行叫做候选行

  ②使用某个候选行来执行子查询

  ③使用子查询的返回值来决定该候选行是出现在最终的结果集中还是被丢弃

  ④重复以上步骤2和3,将所有的候选行处理完毕,得到最终的结果

示例:得到项目是‘研发产品’的雇员的编号

mysql> select num
-> from employee
-> where '研发产品'=(
->   select function
->   from department
->   where d_id=employee.d_id);
+------+
| num |
+------+
| 1 |
| 2 |
+------+

解析:

  1)主查询得到候选行,一行一行的拿去执行子查询;

  2)主查询表employee的候选行的d_id和子查询的d_id匹配,返回值进行where过滤;

  3)符合,加入最终结果集;

  4)不符合,将候选行丢弃,接着进行处理下一个候选行。

带EXISTS关键字的相关子查询(EXISTS存在)

专门判断子查询的结果集是否不为空:

  非空空返回true

  空返回false

当返回的值为true时,外层查询语句将进行查询,否则不进行查询

mysql> select * from employee
-> where exists
-> (select d_name from department where d_id=1004);
Empty set (0.00 sec)

此处内层循环并没有查询到满足条件的结果,因此返回false,外层查询不执行

EXISTS关键字可以与其他的查询条件一起使用,条件表达式与EXISTS关键字之间用AND或者OR来连接

mysql> select * from employee
-> where age>24 and exists
-> (select d_name from department where d_id=1003);
+------+------+--------+------+------+--------------------+
| num | d_id | name | age | sex | homeaddr |
+------+------+--------+------+------+--------------------+
| 1 | 1001 | 张三 | 26 | 男 | 北京市海淀区 |
| 3 | 1002 | 王五 | 25 | 男 | 江西省赣州市 |
+------+------+--------+------+------+--------------------+

SELECT中(非常)常用的子查询操作的更多相关文章

  1. SELECT中常用的子查询操作

    MySQL中的子查询 是在MySQL中经常使用到的一个操作,不仅仅是用在DQL语句中,在DDL语句.DML语句中也都会常用到子查询. 子查询的定义: 子查询是将一个查询语句嵌套在另一个查询语句中: 在 ...

  2. SQL的子查询操作

    对于表中的每一个记录,我们有时候需要提取特殊的或者你需要的记录,要提前做一个表的筛选,之后再对你选出的记录做一个修改,此时你必须使用SQL的子查询操作.如:修改id=5的记录的strContent字段 ...

  3. sqlserver中的 数据转换 与 子查询

    数据类型转换 --cast转换 select CAST(1.23 as int) select CAST(1.2345 as decimal(18,2)) select CAST(123 as var ...

  4. SQL Server中INNER JOIN与子查询IN的性能测试

    这个月碰到几个人问我关于"SQL SERVER中INNER JOIN 与 IN两种写法的性能孰优孰劣?"这个问题.其实这个概括起来就是SQL Server中INNER JOIN与子 ...

  5. sqlserver中的数据转换与子查询

    数据类型转换 --cast转换 select CAST(1.23 as int) select CAST(1.2345 as decimal(18,2)) select CAST(123 as var ...

  6. SQL中带有NOT IN 子查询改写

    报表程序中的一段SQL运行很慢,代码如下: 优化前: 耗时:1337s INSERT INTO PER_LTE_ZIB_PB_COMMISSION_07 SELECT P.TOPACTUALID, Q ...

  7. 详细讲述MySQL中的子查询操作 (来自脚本之家)

    继续做以下的前期准备工作: 新建一个测试数据库TestDB: ? 1 create database TestDB; 创建测试表table1和table2: ? 1 2 3 4 5 6 7 8 9 1 ...

  8. EF Core中Join可以进行子查询

    我们来看看下面的代码,这个代码是一个INNER JOIN的EF Core查询,其中用SubCategory表INNER JOIN了SubCategoryLanguage表,但是我们需要在SubCate ...

  9. Oracle-with c as (select ......) 实现多次调用子查询结果

    with c as  (select a.trandt,sum(a.tranam) tranam from tran a group by a.trandt )   #将子查询抽取出来,以后可以直接重 ...

随机推荐

  1. <context:property-placeholder/>元素

    <context:property-placeholder/>元素 PropertyPlaceholderConfigurer实现了BeanFactoryPostProcessor接口,它 ...

  2. (1)写给Web初学者的教案-----学习Web的知识架构

    1:学习Web的知识架构 前文中我们简单的介绍了一些关于Web的基本知识,这里任老师再次强调一下凡是用浏览器打开的网站我们就称之为Web应用程序(B/S结构).除此之外其它需要下载安装的软件或是手机  ...

  3. 去掉标题栏的方法(使用requestWindowFeature(Window.FEATURE_NO_TITLE);为什么失效)

    使用requestWindowFeature(Window.FEATURE_NO_TITLE)隐藏标题栏失效的原因,可能是activity继承的是AppCompatActivity.下面详细介绍了使用 ...

  4. 【阿里聚安全技术公开课】移动APP漏洞风险与解决方案

    阿里云·云栖社区携手阿里聚安全打造阿里安全技术公开课,带你一探互联网安全的风采 关于移动APP安全 移动App是大家使用手机每天接触最多的东西,然而在移动APP开发中,由于一些开发工程师对安全的不重视 ...

  5. View 的measure 和onMeasure

    p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px "PingFang SC"; color: #454545 } p.p2 ...

  6. [LeetCode] Range Sum Query - Mutable 题解

    题目 题目 思路 一看就是单点更新和区间求和,故用线段树做. 一开始没搞清楚,题目给定的i是从0开始还是从1开始,还以为是从1开始,导致后面把下标都改掉了,还有用区间更新的代码去实现单点更新,虽然两者 ...

  7. PHP之流程的控制

       在一个公司中,员工肯定会有高层.中层和普通员工的,这样如果在某个公司员工遇到某种问题,需要请假.或者提一些请求的时候,就会需要去申请,申请的时候有的是可以直接和上级申请的,有时比较重要的事情,是 ...

  8. webService常见问题

    1.普通字符串(日期形式)转换为XMLGregorianCalendar SimpleDateFormat simpleDateFormat =new SimpleDateFormat("y ...

  9. python3编码问题终结者--还搞不懂你来找我

    python unicode bytes str 编码 首先需要说明一下,该篇文章是以python3为基础的,python2是否适合没有验证过.由于python编码问题确实比较多,文章篇幅可能较长,请 ...

  10. xlrd的使用详细介绍以及基于Excel数据参数化实例详解

    1.安装xlrd xlrd是python用于读取excel的第三方扩展包,所以在使用xlrd前,需要使用以下命令来安装xlrd.pip install xlrd 在使用这个命令之前先确定自己有没有安装 ...