mysql 为什么子查询产生语法错误,而整体查询却不报错且返回正确结果

查出选修了数据库和数学这两门课程的学生姓名和院系
数据库表,字段信息如下

课程表course:
select * from course ;
cno    cname
1001    数学
1002    数据库
1003    语文

学生表student:
select * from student ;
sno         sname  sex   age   sdept
20121011    张三  男 18  计算机
20131011    李四  男 17  计算机
20131012    王五  女 16  信息
20131013    赵六  女 19  信息

选课表sc:
    select * from sc;
sno         cno    grade
20131011    1001    100
20131012    1001    70
20131011    1002    98

sql:

SELECT 
    sname, sdept

from Student 

WHERE sno IN ( 
    SELECT sno FROM sc WHERE cno IN ( 
        SELECT cno FROM course WHERE cname = '数学' 
            AND sno IN ( 
                SELECT sno FROM sc WHERE cno IN ( 
                    SELECT cno FROM course 
                    WHERE cname = '数据库' ))));

运行结果为:

sname  sdept
李四  计算机

期望的结果是运行失败,因为针对第三层子查询来说,提示语法错误:

SELECT cno FROM course WHERE cname = '数学' AND sno IN ( 
    SELECT sno FROM sc WHERE cno IN ( 
        SELECT cno FROM course WHERE cname = '数据库' ))

[Err] 1054 - Unknown column 'sno' in 'IN/ALL/ANY subquery'

疑问:为什么在子查询失败的情况下,整体查询能正常执行???

估计是你这个版本的mysql有这个容错机制,因为你前面几句查询都是对的,所以他直接忽略后面的错误

个人认为是IN的语法引起的,建议用EXISTS代替,IN语法在查询数据集中如果有空记录会造成查询不正确,可能在整体查询上会作为空来执行,具体可以百度一下IN的问题

子查询报错是因为没有找到sno得那个字段,你sno在学生跟选课表里才有,你单独拎第三段出来去查sno肯定查不到给你报错啊

放在子查询里面查的话他这个sno对的就是上一句sql得sno字段,好像是这样。记得不太清,有错得话望纠正

换成inner join看下,不要搞那么多嵌套in。比如

SELECT sname, sdept

  from Student t7

 inner join (SELECT sno FROM sc) t6
    on t6.sno = t7.sno
 inner join (SELECT cno, sno FROM course WHERE cname = '数学') t5
    on t5.cno = t6.cno
 inner join (SELECT sno FROM sc) t1
    on t1.sno = t5.sno
 inner join (SELECT cno FROM course WHERE cname = '数据库') t2
    on t2.cno = t1.cno;

这是MySQL的优化机制,虽然你写错了in查询,但是优化之后的sql语句,自动帮你把那个不存在的字段放在正确的位置上了。你可以先:

explain [你的sql语句];
show warnings;

查看优化之后的语句