【图书推荐】《MySQL 9从入门到性能优化(视频教学版)》-CSDN博客
《MySQL 9从入门到性能优化(视频教学版)(数据库技术丛书)》(王英英)【摘要 书评 试读】- 京东图书 (jd.com)
子查询指一个查询语句嵌套在另一个查询语句内部的查询,这个特性从MySQL 4.1开始引入。在SELECT子句中先计算子查询,子查询结果作为外层另一个查询的过滤条件,查询可以基于一张表或者多张表。子查询中常用的操作符有ANY(SOME)、ALL、IN、EXISTS。子查询可以添加到SELECT、UPDATE和DELETE语句中,而且可以进行多层嵌套。子查询中也可以使用比较运算符,如"<""<="">"">="和"!="等。本节将介绍如何在SELECT语句中嵌套子查询。
5.5.1 带ANY、SOME关键字的子查询
ANY和SOME是同义词,表示满足其中任意一个条件。它们允许创建一个表达式对子查询的返回值列表进行比较,只要满足内层子查询中的任何一个比较条件,就返回一个结果作为外层查询的条件。
下面定义两张表tbl1和tbl2:
CREATE table tbl1 ( num1 INT NOT NULL);
CREATE table tbl2 ( num2 INT NOT NULL);
分别向两张表中插入数据:
INSERT INTO tbl1 values(1), (5), (13), (27);
INSERT INTO tbl2 values(6), (14), (11), (20);
ANY关键字接在一个比较操作符的后面,表示若与子查询返回的任何值比较的结果为TRUE,则返回TRUE。
【例5.53】返回表tbl2中的num2列的所有值,然后将表tbl1中的num1列的值与num2列的值进行比较,只要num1列中的值大于num2列中的任何一个值,即为符合查询条件的结果。
mysql> SELECT num1 FROM tbl1 WHERE num1 > ANY (SELECT num2 FROM tbl2);
+------+
| num1 |
+------+
| 13 |
| 27 |
+------+
在子查询中,返回的是表tbl2的num2列的值,即(6,14,11,20),然后将表tbl1中的num1列的值与(6,14,11,20)进行比较,只要num1列中的值大于(6,14,11,20)中的任意一个,即为符合条件的结果,因此返回的结果为(13,27)。
5.5.2 带ALL关键字的子查询
ALL关键字与ANY和SOME不同,使用ALL时需要同时满足所有内层查询的条件。
ALL关键字接在一个比较操作符的后面,表示与子查询返回的所有值进行比较,若结果为TRUE,则返回TRUE。
下面修改【例5.53】,用ALL关键字替换ANY。
【例5.54】返回表tbl1中比表tbl2的num2列所有值都大的值,SQL语句如下:
mysql> SELECT num1 FROM tbl1 WHERE num1 > ALL (SELECT num2 FROM tbl2);
+------+
| num1 |
+------+
| 27 |
+------+
在子查询中,返回的是表tbl2的值,即num2列的所有(6,14,11,20),然后将表tbl1中的num1列的值与之进行比较,大于所有num2列值的num1值只有27,因此返回结果为27。
5.5.3 带EXISTS关键字的子查询
EXISTS关键字后面的参数是一个任意的子查询,系统对子查询进行运算以判断它是否返回行,如果至少返回一行,那么EXISTS返回的结果为TRUE,此时外层查询语句将进行查询;如果子查询没有返回任何行,那么EXISTS返回的结果是FALSE,此时外层查询语句将不进行查询。
【例5.55】查询表suppliers中是否存在s_id=107的水果供应商,如果存在,则查询表fruits中的记录,SQL语句如下:
mysql> SELECT * FROM fruits WHERE EXISTS (SELECT s_name FROM suppliers WHERE s_id = 107);
+------+-------+-----------+---------+
| f_id | s_id | f_name | f_price |
+------+-------+-----------+---------+
| a1 | 101 | apple | 5.20 |
| a2 | 103 | apricot | 2.20 |
| b1 | 101 | blackberry| 10.20 |
| b2 | 104 | berry | 7.60 |
| b5 | 107 | xxxx | 3.60 |
| bs1 | 102 | orange | 11.20 |
| bs2 | 105 | melon | 8.20 |
| c0 | 101 | cherry | 3.20 |
| l2 | 104 | lemon | 6.40 |
| m1 | 106 | mango | 15.70 |
| m2 | 105 | xbabay | 2.60 |
| m3 | 105 | xxtt | 11.60 |
| o2 | 103 | coconut | 9.20 |
| t1 | 102 | banana | 10.30 |
| t2 | 102 | grape | 5.30 |
| t4 | 107 | xbababa | 3.60 |
+------+------+------------+---------+
由结果可以看到,内层查询结果表明表suppliers中存在s_id=107的记录,因此EXISTS表达式返回TRUE;外层查询语句接收TRUE之后对表fruits进行查询,返回所有的记录。
EXISTS关键字可以和条件表达式一起使用。
【例5.56】查询表suppliers中是否存在s_id=107的水果供应商,如果存在,则查询表fruits中的f_price>10.20的记录,SQL语句如下:
mysql> SELECT * FROM fruits WHERE f_price>10.20 AND EXISTS (SELECT s_name FROM suppliers WHERE s_id = 107);
+------+------+--------+---------+
| f_id | s_id | f_name | f_price |
+------+------+--------+---------+
| bs1 | 102 | orange | 11.20 |
| m1 | 106 | mango | 15.70 |
| m3 | 105 | xxtt | 11.60 |
| t1 | 102 | banana | 10.30 |
+------+------+--------+---------+
由结果可以看到,内层查询结果表明表suppliers中存在s_id=107的记录,因此EXISTS表达式返回TRUE;外层查询语句接收TRUE之后根据查询条件f_price > 10.20对表fruits进行查询,返回结果为4条f_price>10.20的记录。
NOT EXISTS与EXISTS的使用方法相同,返回的结果相反。子查询如果至少返回一行,那么NOT EXISTS返回的结果为FALSE,此时外层查询语句将不进行查询;如果子查询没有返回任何行,那么NOT EXISTS返回的结果是TRUE,此时外层查询语句将进行查询。
【例5.57】查询表suppliers中是否存在s_id=107的水果供应商,如果不存在,则查询表fruits中的记录,SQL语句如下:
mysql> SELECT * FROM fruits WHERE NOT EXISTS (SELECT s_name FROM suppliers WHERE s_id = 107);
Empty set (0.00 sec)
查询语句SELECT s_name FROM suppliers WHERE s_id = 107对表suppliers进行查询并返回了一条记录,因此NOT EXISTS表达式返回FALSE,外层表达式接收FALSE,将不再查询表fruits中的记录。