13.2.13 子查询 下面是本文用到的测试数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 SET FOREIGN_KEY_CHECKS= 0 ;DROP TABLE IF EXISTS `emp_table`;CREATE TABLE `emp_table` ( `emp_id` int (11 ) NOT NULL AUTO_INCREMENT, `emp_name` varchar (255 ) DEFAULT NULL , `manager_id` int (11 ) DEFAULT NULL , PRIMARY KEY (`emp_id`), KEY `manager_id` (`manager_id`), CONSTRAINT `emp_table_ibfk_1` FOREIGN KEY (`manager_id`) REFERENCES `emp_table` (`emp_id`) ) ENGINE= InnoDB AUTO_INCREMENT= 5 DEFAULT CHARSET= utf8; INSERT INTO `emp_table` VALUES ('1' , '唐僧' , null );INSERT INTO `emp_table` VALUES ('2' , '孙悟空' , '1' );INSERT INTO `emp_table` VALUES ('3' , '猪八戒' , '1' );INSERT INTO `emp_table` VALUES ('4' , '沙僧' , '1' );DROP TABLE IF EXISTS `student_table`;CREATE TABLE `student_table` ( `student_id` int (11 ) NOT NULL AUTO_INCREMENT, `student_name` varchar (255 ) DEFAULT NULL , `java_teacher` int (11 ) DEFAULT NULL , PRIMARY KEY (`student_id`), KEY `java_teacher` (`java_teacher`), CONSTRAINT `student_table_ibfk_1` FOREIGN KEY (`java_teacher`) REFERENCES `teacher_table` (`teacher_id`) ) ENGINE= InnoDB AUTO_INCREMENT= 8 DEFAULT CHARSET= utf8; INSERT INTO `student_table` VALUES ('1' , '张三' , '1' );INSERT INTO `student_table` VALUES ('2' , '张三' , '1' );INSERT INTO `student_table` VALUES ('3' , '李四' , '1' );INSERT INTO `student_table` VALUES ('4' , '王五' , '2' );INSERT INTO `student_table` VALUES ('5' , '_王五' , '2' );INSERT INTO `student_table` VALUES ('6' , null , '2' );INSERT INTO `student_table` VALUES ('7' , '赵六' , '3' );DROP TABLE IF EXISTS `teacher_table`;CREATE TABLE `teacher_table` ( `teacher_id` int (11 ) NOT NULL AUTO_INCREMENT, `teacher_name` varchar (255 ) DEFAULT NULL , PRIMARY KEY (`teacher_id`) ) ENGINE= InnoDB AUTO_INCREMENT= 4 DEFAULT CHARSET= utf8; INSERT INTO `teacher_table` VALUES ('1' , 'Yeeku' );INSERT INTO `teacher_table` VALUES ('2' , 'Leegang' );INSERT INTO `teacher_table` VALUES ('3' , 'Martine' );
子查询就是指在査询语句中嵌套另一个査询 ,子査询可以支持多层嵌套。对于一个普通的查询语句而言,子查询可以出现在两个位置:
出现在from
语句后,此时子查询的结果可以看成一个数据表,这种用法也被称为行内视图,因为该子查询的实质就是一个临时视图。
出现在where
条件后作为过滤条件的值。 使用子查询时要注意如下几点。
子查询要用括号括起来。
把子查询当成数据表时(出现在from
之后),可以为该子查询起别名,尤其是作为前缀来限定数据列时,必须给子查询起别名。
对于把子查询当做数据表来用,只是把之前的表名变成子查询(也可为子查询起别名),其他部分与普通查询没有任何区别。下面的SQL
语句示范了把子查询当成数据表的用法。
1 2 3 select * from (select * from student_table) twhere t.java_teacher> 1 ;
运行效果:
1 2 3 4 5 6 7 8 9 10 11 12 mysql> select * from (select * from student_table) t where t.java_teacher>1 ; +------------+--------------+--------------+ | student_id | student_name | java_teacher | +------------+--------------+--------------+ | 4 | 王五 | 2 | | 5 | _王五 | 2 | | 6 | NULL | 2 | | 7 | 赵六 | 3 | +------------+--------------+--------------+ 4 rows in set
把子查询当成数据表的用法更准确地说是当成视图,可以把上面的SQL
语句理解成在执行查询时创建了一个临时视图,该视图名为t
,所以这种临时创建的视图也被称为行内视图
。 还有一种情形:把子查询当成where
条件中的值,如果子查询返回单行、单列值,则被当成一个标量值使用,也就可以使用单行记录比较运算符。例如如下SQL
语句:
1 2 3 4 5 6 select * from student_tablewhere java_teacher > ( select teacher_id from teacher_table where teacher_name = 'Yeeku' );
运行结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 mysql> select * from student_table; +------------+--------------+--------------+ | student_id | student_name | java_teacher | +------------+--------------+--------------+ | 1 | 张三 | 1 | | 2 | 张三 | 1 | | 3 | 李四 | 1 | | 4 | 王五 | 2 | | 5 | _王五 | 2 | | 6 | NULL | 2 | | 7 | 赵六 | 3 | +------------+--------------+--------------+ 7 rows in set mysql> select * from teacher_table; +------------+--------------+ | teacher_id | teacher_name | +------------+--------------+ | 1 | Yeeku | | 2 | Leegang | | 3 | Martine | +------------+--------------+ 3 rows in set mysql> select * from student_table where java_teacher > ( select teacher_id from teacher_table where teacher_name = 'Yeeku' ); +------------+--------------+--------------+ | student_id | student_name | java_teacher | +------------+--------------+--------------+ | 4 | 王五 | 2 | | 5 | _王五 | 2 | | 6 | NULL | 2 | | 7 | 赵六 | 3 | +------------+--------------+--------------+ 4 rows in set mysql>
上面查询语句中的子査询将返回一个单行
、单列
的值(该值就是1
),如果把上面查询语句的括号部分换成1
,那么这条语句就再简单不过了,相同功能的查询结果如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 mysql> select * from student_table where java_teacher > 1 ; +------------+--------------+--------------+ | student_id | student_name | java_teacher | +------------+--------------+--------------+ | 4 | 王五 | 2 | | 5 | _王五 | 2 | | 6 | NULL | 2 | | 7 | 赵六 | 3 | +------------+--------------+--------------+ 4 rows in set mysql>
放在Where
子句的子查询会把单行,单列的返回值当成标量处理.
如果子査询返回多个值,则需要使用in
、any
和all
等关键字,in
可以单独使用,与前面介绍比较运算符时所讲的in
完全一样,此时可以把子查询返回的多个值当成一个值列表。如下SQL
语句所示:
1 2 3 4 5 6 select * from student_tablewhere student_id in ( select teacher_id from teacher_table );
运行效果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 mysql> select * from student_table; +------------+--------------+--------------+ | student_id | student_name | java_teacher | +------------+--------------+--------------+ | 1 | 张三 | 1 | | 2 | 张三 | 1 | | 3 | 李四 | 1 | | 4 | 王五 | 2 | | 5 | _王五 | 2 | | 6 | NULL | 2 | | 7 | 赵六 | 3 | +------------+--------------+--------------+ 7 rows in set mysql> select * from teacher_table; +------------+--------------+ | teacher_id | teacher_name | +------------+--------------+ | 1 | Yeeku | | 2 | Leegang | | 3 | Martine | +------------+--------------+ 3 rows in set mysql> select * from student_table where student_id in ( select teacher_id from teacher_table ); +------------+--------------+--------------+ | student_id | student_name | java_teacher | +------------+--------------+--------------+ | 1 | 张三 | 1 | | 2 | 张三 | 1 | | 3 | 李四 | 1 | +------------+--------------+--------------+ 3 rows in set mysql>
上面查询语句中的子查询将返回多个值,这多个值将被当成一个值列表,只要student_id
与该值列表中的任意一个值相等,就可以选出这条记录。any
和all
可以与>
、≥
、<
、<
、<>
、=
等运算符结合使用,与any
结合使用分别表示大于、大于等于、小于、小于等于
、不等于
、等于
其中任意一个值 ; 与叫all
结合使用分别表示大于、大于等于、小于、小于等于、不等于、等于全部值 。从上面介绍中可以看出,=any
的作用与in
的作用相同。如下SQL
语句使用=any
来代替上面的in
:
1 2 3 4 5 select * from student_tablewhere student_id = any ( select teacher_id from teacher_table );
运行结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 mysql> select * from student_table where student_id = any ( select teacher_id from teacher_table ); +------------+--------------+--------------+ | student_id | student_name | java_teacher | +------------+--------------+--------------+ | 1 | 张三 | 1 | | 2 | 张三 | 1 | | 3 | 李四 | 1 | +------------+--------------+--------------+ 3 rows in set
<ANY
只要小于值列表中的最大值即可,
>ANY
只要大于值列表中的最小值即可。
<all
要求小于值列表中的最小值,
>all
要求大于值列表中的最大值 下面的SQL
语句选出student_table
表中student_id
大于teacher_table
表中所有teacher_id
的记录。1 2 3 4 5 6 select * from student_tablewhere student_id > all ( select teacher_id from teacher_table );
还有一种子查询可以返回多行、多列,此时where
子句中应该有对应的数据列,并使用圆括号将多个数据列组合起来。如下SQL
语句所示:1 2 3 select * from student_tablewhere (student_id,student_name) = any (select teacher_id,teacher_name from teacher_table);