子查询是指一个查询语句嵌套在另一个查询语句内部的查询。在select子句中先计算子查询,子查询结果作为外层另一个查询的过滤条件,查询可以基于一个表或者多个表。
子查询中常用的操作符有any(some)、all、in、exists。子查询可以添加到select、update和delete语句中,而且可以进行多层嵌套。子查询中也可以使用比较运算符,如"<","<=",">",">=“和”!="。
(1)带any、some关键字的子查询(2)带all关键字的子查询
(3)带exists关键字的子查询
(4)带in关键字的子查询
(5)带比较运算符的子查询
(1)带any、some关键字的子查询
any和some关键字是同义词,表示满足其中任一条件,允许创建一个表达式对子查询的返回值列表进行比较,只要满足内层子查询中的任何一个比较条件,就返回一个结果作为外层查询的条件。
下面定义两个表tbl1和tbl2,并向两个表中插入数据:
mysql> create table tbl1( num1 int not null);
Query OK, 0 rows affected (0.13 sec)
mysql> create table tbl2(num2 int not null);
Query OK, 0 rows affected (0.10 sec)
mysql> insert into tbl1 values(1),(5),(13),(27);
Query OK, 4 rows affected (0.05 sec)
Records: 4 Duplicates: 0 Warnings: 0
mysql> insert into tbl2 values(6),(14),(11),(20);
Query OK, 4 rows affected (0.06 sec)
Records: 4 Duplicates: 0 Warnings: 0
any关键字接在一个比较操作符后面,表示若与子查询返回的任何职比较为true,则返回true。
【例】返回tbl2表的所有num2列,然后将tbl1中的num1的值与之进行比较,只要大于num2的任何一个值,即为符合条件的结果。
mysql> select num1 from tbl1 where num1 > any(select num2 from tbl2);
+------+
| num1 |
+------+
| 13 |
| 27 |
+------+
2 rows in set (0.00 sec)
(2)带all关键字的子查询
- all关键字需要同时满足所有内层查询的条件。
- all关键字接在一个比较操作符后面,表示与子查询返回的所有值比较为true,则返回true。
【例】返回tbl1表中比tbl2表num2列所有值都大的值,SQL语句如下:
mysql> select num1 from tbl1 where num1 > all(select num2 from tbl2);
+------+
| num1 |
+------+
| 27 |
+------+
1 row in set (0.00 sec)
(3)带exists关键字的子查询
- exists关键字后面的参数是一个任意的子查询,系统对子查询进行运算以判断它是否返回行,如果至少返回一行,那么exists的结果为true,此时外层查询语句将进行查询;如果子查询没有返回任何行,那么exists返回的结果是false,此时外层语句将不进行查询。
【例1】查询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 |
+------+------+------------+---------+
| 12 | 104 | lemon | 6.40 |
| 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 |
| 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 | xbabay | 3.60 |
+------+------+------------+---------+
16 rows in set (0.00 sec)
由结果可知,内层查询结果表明suppliers表中存在s_id=107的记录,因此exists表达式返回true;外层查询语句接收true之后对表fruits进行查询,返回所有记录。
【例2】查询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 |
+------+------+--------+---------+
4 rows in set (0.00 sec)
可以看到,内层查询表名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,此时外层语句将进行查询。
【例3】查询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)
可以看到,内层查询返回结果为false,外层表达式接收false将不再查询fruits表中的记录。
注意:exists 和 not exists的结果只取决于是否会返回行,而不取决于这些行的内容,所以这个子查询输入列表通常是无关紧要的。
(4)带in关键字的子查询
- in关键字进行子查询时,内层查询语句仅仅返回一个数据列,这个数据列里的值将提供给外层查询语句进行比较操作。
【例1】在orderitems表中查询f_id为c0的订单号,并根据订单号查询具有订单号的客户c_id,SQL语句如下:
mysql> select c_id from orders where o_num in
-> (select o_num from orderitems where f_id = 'c0');
+-------+
| c_id |
+-------+
| 10004 |
| 10001 |
+-------+
2 rows in set (0.00 sec)
上面的语句是下面查询方式的简写:
mysql> select o_num from orderitems where f_id = 'c0';
+-------+
| o_num |
+-------+
| 30003 |
| 30005 |
+-------+
2 rows in set (0.00 sec)
mysql> select c_id from orders where o_num in (30003,30005);
+-------+
| c_id |
+-------+
| 10004 |
| 10001 |
+-------+
2 rows in set (0.00 sec)
下面介绍与in相反的not in关键字:
【例2】与例1类似,但select语句中使用not in 关键字。SQL语句如下:
mysql> select c_id from orders where o_num not in
-> (select o_num from orderitems where f_id ='c0');
+-------+
| c_id |
+-------+
| 10001 |
| 10003 |
| 10005 |
+-------+
3 rows in set (0.00 sec)
可以看到返回了三个表,查看orders中的记录可知,c_id等于10001的客户的订单不止一个:
mysql> select * from orders;
+-------+---------------------+-------+
| o_num | o_date | c_id |
+-------+---------------------+-------+
| 30001 | 2008-09-01 00:00:00 | 10001 |
| 30002 | 2008-09-12 00:00:00 | 10003 |
| 30003 | 2008-09-30 00:00:00 | 10004 |
| 30004 | 2008-10-03 00:00:00 | 10005 |
| 30005 | 2008-10-08 00:00:00 | 10001 |
+-------+---------------------+-------+
5 rows in set (0.00 sec)
结果只是排除了订单号,但仍然有可能选择同一个客户。
子查询的功能也可以通过连接查询完成,但子查询使得MySQL代码更容易阅读和编写。
(5)带比较运算符的子查询
【例1】在suppliers表中查询s_city等于"Tianjin"的供应商s_id,然后在fruits表中查询所有该供应商提供的水果的种类,SQL语句如下:
mysql> select s_id,f_name from fruits
-> where s_id =
-> (select s1.s_id from suppliers as s1 where s1.s_city = 'Tianjin');
+------+------------+
| s_id | f_name |
+------+------------+
| 101 | apple |
| 101 | blackberry |
| 101 | cherry |
+------+------------+
3 rows in set (0.00 sec)
【例2】在suppliers表中查询s_city等于"Tianjin"的供应商,s_id,然后在fruits表中查询所有非该供应商提供的水果的种类,SQL语句如下:
mysql> select s_id , f_name from fruits
-> where s_id <>
-> (select s1.s_id from suppliers as s1 where s1.s_city ='Tianjin');
+------+---------+
| s_id | f_name |
+------+---------+
| 104 | lemon |
| 103 | apricot |
| 104 | berry |
| 107 | xxxx |
| 102 | orange |
| 105 | melon |
| 106 | mango |
| 105 | xbabay |
| 105 | xxtt |
| 103 | coconut |
| 102 | banana |
| 102 | grape |
| 107 | xbabay |
+------+---------+
13 rows in set (0.00 sec)