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. 详细讲述MySQL中的子查询操作 (来自脚本之家)

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

  3. J2EE进阶(十七)Hibernate中常用的HQL查询方法(getHibernateTemplate())

    J2EE进阶(十七)Hibernate中常用的HQL查询方法(getHibernateTemplate())   当我们使用Hibernate进行数据的CRUD操作时,利用模版进行操作不失为一种方法. ...

  4. SQL的子查询操作

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

  5. 警惕 MySql 更新 sql 的 WHERE 从句中的 IN() 子查询时出现的性能陷阱

    警惕 MySql 更新 sql 的 WHERE 从句中的 IN() 子查询时出现的性能陷阱 以下文章来源:https://blog.csdn.net/defonds/article/details/4 ...

  6. getHibernateTemplate()(Spring中常用的hql查询方法)

    Spring中常用的hql查询方法(getHibernateTemplate()) --------------------------------- 一.find(String queryStrin ...

  7. SELECT列表中的标量子查询

    发现了一种表连接新的写法,以前还没有这样写过或者见别人写过.跟同学聊天他们公司却很多人这样写,看来真的要学学sql了 表 CREATE TABLE `t_book` ( `FId` ) NOT NUL ...

  8. EF Core中执行Sql语句查询操作之FromSql,ExecuteSqlCommand,SqlQuery

    一.目前EF Core的版本为V2.1 相比较EF Core v1.0 目前已经增加了不少功能. EF Core除了常用的增删改模型操作,Sql语句在不少项目中是不能避免的. 在EF Core中上下文 ...

  9. 警惕 MySql 更新 sql 的 WHERE 从句中的 IN() 子查询时出现的陷阱

    mer_stage 表有 216423 条记录,DDL: CREATE TABLE `mer_stage` ( `STAGE_ID` int(11) NOT NULL AUTO_INCREMENT, ...

随机推荐

  1. JS复制内容到剪贴板(兼容FF/Chrome/Safari所有浏览器)

    现在浏览器种类也越来越多,诸如 IE.Firefox.Chrome.Safari等等,因此现在要实现一个js复制内容到剪贴板的小功能就不是一件那么容易的事了. 在FLASH 9 时代,有一个通杀所有浏 ...

  2. 【转】MySQL count(*)速度慢优化

    select count(*)是MySQL中用于统计记录行数最常用的方法. count方法可以返回表内精确的行数,每执行一次都会进行一次全表扫描, 以避免由于其他连接进行delete和insert引起 ...

  3. applicationContext.xml报错org.springframework.orm.hibernate3.LocalSessionFactoryBean not found

    applicationContext.xml报错org.springframework.orm.hibernate3.LocalSessionFactoryBean not found 解决办法: 1 ...

  4. 第三百七十六节,Django+Xadmin打造上线标准的在线教育平台—创建用户操作app,在models.py文件生成5张表,用户咨询表、课程评论表、用户收藏表、用户消息表、用户学习表

    第三百七十六节,Django+Xadmin打造上线标准的在线教育平台—创建用户操作app,在models.py文件生成5张表,用户咨询表.课程评论表.用户收藏表.用户消息表.用户学习表 创建名称为ap ...

  5. googletest进行单元测试(使用cmake编译)

    一.前提: 1.假定你的系统为centos6系列 2.假定你已经安装了基本的编译环境,gcc,g++4.4.7 3.假定你已经设置了环境变量:KDS_MOBILE_STOCK_HOME 4.假定你已经 ...

  6. Unity 各个组件参数总结

    今天在蛮牛教育上学习了NGUI的课程下面给大家总结了一些小知识点希望对大家有帮助UICamera-可以添加到任何相机,包含事件系统.UICamera是每个UI的重要组成部分.它负责发送Camera中所 ...

  7. svn -- svn权限控制

    权限控制 问题:当前采用单仓库或多仓库配置中,所有的文件权限都是可读写的,这样就会存在一个问题,只要任何知道了我们的访问地址,那么都可以对文件进行读写操作. 1.为什么需要权限控制 打开服务器端的项目 ...

  8. Android多国语言的value文件夹命名方式

    在res目錄下建立不同名稱的values文件來調用不同的語言包Values文件匯總如下:中文(中國):values-zh-rCN中文(台灣):values-zh-rTW中文(香港):values-zh ...

  9. IE8不支持数组的indexOf方法

    在IE8下有个js错误,但是在其它浏览器下(Firefox, Chrome, IE9)下面都很正常.后来调试发现原因是在IE8下,js数组没有indexOf方法. 在使用indexOf方法前,执行一下 ...

  10. Eclipse文件首部自动加 作者时间

    Window -> Preferences -> Java -> Code Style -> Code templates -> (in right-hand pane) ...