从头开始学MySQL--------子查询(5)
7.5.1 带ANY、SOME、ALL的子查询
子查询是指一个查询语句嵌套在另外一个查询语句中的查询。
在SELECT子句中先计算子查询,子查询结果作为来外外层另外一个查询的过滤条件。即另外一个查询的查询条件就是子查询中返回的数据记录。
CREATE TABLE tbA(num1 INT NOT NULL);
CREATE TABLE tbB(num2 INT NOT NULL);
INSERT INTO tbA(num1) VALUES(1),(5),(13),(27);
INSERT INTO tbB(num2) VALUES(6),(14),(11),(20);
ANY与SOME是一个意思,它表示只要满足任意一个条件,就返回此结果。
SELECT
num1
FROM
tbA
WHERE
num1 > ANY (SELECT num2 FROM tbB)
ALL是满足所有条件,才返回结果。
SELECT
num1
FROM
tbA
WHERE
num1 > ALL (SELECT num2 FROM tbB)
7.5.4 带IN关键词查询
内查询(嵌套查询)返回的是一个数据列。
还是那个选导师的例子。
DROP TABLE IF EXISTS t_teacher;
CREATE TABLE t_teacher(
id INT(11) PRIMARY KEY AUTO_INCREMENT,
teacName VARCHAR(255) NOT NULL UNIQUE,
age INT(11)
);
INSERT INTO t_teacher(teacName,age) VALUES('田教授数据库原理',44),('秀芳姐C语言',31),
('黄金城通信原理',36),('韩院长',55);
DROP TABLE IF EXISTS t_student;
CREATE TABLE t_student(
id INT(11),
name VARCHAR(255),
teacherId INT(11),
CONSTRAINT fk_stu_teac FOREIGN KEY(teacherId) REFERENCES t_teacher(id)
);
-- 每个学生选择一个导师,也可以不选,即没有导师
INSERT INTO t_student(id,name,teacherId) VALUES(1,'大宇',4),(2,'小雨',3),
(3,'小大宇',2),(4,'学霸',NULL);
如上所示,除了学霸之外的所有学生都已经选好了导师,而学霸的导师是NULL,他要自立门户。
现需求:查询没有选择导师的学生,预期结果是查询出来学霸。
SELECT
t_student.id,
t_student.name
FROM t_student
WHERE t_student.id NOT IN
(
-- 先查询出来已经选好导师的学生的ID
SELECT t_student.id
FROM t_student
JOIN t_teacher ON t_student.teacherId = t_teacher.id
)
单独执行子查询,看下是什么结果。
SELECT t_student.id
FROM t_student
JOIN t_teacher ON t_student.teacherId = t_teacher.id
原来子查询返回的是一个序列,因此原来的SQL可以等价于
SELECT
t_student.id,
t_student.name
FROM t_student
WHERE t_student.id NOT IN
(
1,2,3
)
拨云见日
原来,内层的嵌套查询,或者说是子查询,返回的原来是一个序列。这就可以解释嵌套查询返回多列结果会报错的原因。
另外,带嵌套查询的SQL语句,其实是分两步进行的,先执行嵌套查询并返回序列,再执行外层查询,条件为序列。
7.5.5 带比较运算符的子查询
现在的需求是:找出不是田教授带的学生。
思路是先找到田教授的ID,再在学生表里面判断导师ID不是此ID的学生的值。
SELECT
t_student.id,
t_student.name,
t_student.teacherId AS 导师ID
FROM t_student
WHERE t_student.teacherId !=
(
SELECT t_teacher.id
FROM t_teacher WHERE t_teacher.teacName LIKE '%田%'
)
--单独执行
SELECT t_teacher.id
FROM t_teacher WHERE t_teacher.teacName LIKE '%田%'
--结果为
--- id ---
--- 1 ---
--上述SQL可以被替换为
SELECT
t_student.id,
t_student.name,
t_student.teacherId AS 导师ID
FROM t_student
WHERE t_student.teacherId != 1
根据查询结果来看,好像是有点问题的,因为学霸的teacherId列的值是NULL,NULL != 1 的运算结果是NULL,所以在返回结果中没有显示学霸这个学生记录。这也说明了在嵌套查询中,注意NULL的列可能会影响查询的结果。
本小节希望说明的是,子查询其实就是返回的一个序列,外层查询用子查询的返回结果序列替换掉原来的子查询部分即可。
阅读更多