本节要点
使用子查询作为计算字段
使用子查询过滤数据(IN)
使用子查询过滤数据(EXISTS)
使用子查询作为计算字段
假如有一张老师表teacher(teacher_id,teacher_name,gender)和一张学生表student(student_id,student_name,gender,birth_day,age,class_id,score,teacher_id),考虑一下下面这个查询需求:
(1)、如何同时查询出学生编号、学生姓名、老师编号、老师姓名?
因为学生表中只有老师编号,没有老师姓名,而老师姓名保存在另一个老师表中。那这个查询需求,就需要用到两张表。
对于这个查询需求,就可以使用到我们这节课讲解的子查询。先来看下这个查询需求,SQL语句应该怎么写:
SELECT student_id, student_name, teacher_id, ( SELECT teacher_name FROM teacher WHERE teacher.teacher_id = student.teacher_id ) FROM student
在这个SQL语句里,有两个SELECT,也就是说,在一个SELECT语句里嵌套了另一个SELECT语句。这就是子查询,是子查询作为SELECT的一个计算字段的写法。
在子查询的内部,使用了student表名来引用外部student表的字段,使用teacher表名来引用teacher表的字段。
其实,我们可以简化一些,为这两张表各取一个别名,那么在使用的时候,就可以使用表别名来引用表中的字段。就像下面这个SQL:
SELECT student_id, student_name, teacher_id, ( SELECT teacher_name FROM teacher b WHERE b.teacher_id = a.teacher_id ) FROM student a;
这个SQL语句与上面的SQL语句是等价的。
这里同时使用到了student表中的teacher_id字段和teacher表中的teacher_id字段,为了明确指定到底是哪个表的teacher_id字段,所以使用了表别名。
其实,如果在SQL语句中,对于使用的字段没有歧义,也就是说,没有同时使用到两个表的相同字段,表别名也是可以省略的。
另外,我们假设一下,如果teacher表中,相同的teacher_id具有多条记录,那么对于同一个学生表中的teacher_id的值,可能会在子查询中查到多条记录,这时候应该返回哪一条呢?
实际上,如果发生这样的情况,执行的时候是会报错的:SQL执行错误 #1242 从数据库的响应 Subquery returns more than 1 row。
使用子查询过滤数据(IN)
再考虑下这个查询需求:
(1)、如何获取姓牛的老师教了哪些学生?
一般来说,可能需要分两步来实现。
第1步:从老师表中查出所有姓牛的老师。
SELECT teacher_id,teacher_name FROM teacher WHERE teacher_name like '牛%’;
第2步:使用IN操作符,将姓牛老师的编号列出来,然后从学生表中查出需要的数据。
SELECT student_id,student_name FROM student WHERE teacher_id IN ('T0010','T0011');
一般情况下,分两步来写,也能得到我们想要的结果。可是也存在两个问题。
问题一:如果姓牛的老师太多(比如超过了500人),如果将所有老师的编号都列出来,那SQL语句就太长了;
问题二:这样写,也需要两步来实现我们的查询需求,实现起来太复杂了;
那么,可不可以使用一句简单的SQL,就搞定这个查询需求呢?
实际上,我们知道,在IN操作符后面的括号里面,是明确列出了一个姓牛老师的老师编号的集合,而上面的第1步的SELECT语句,也是返回了一个相同的集合。
那么,也就可以使用SELECT语句替换掉IN操作符后面括号里的内容,像下面这样:
SELECT student_id,student_name FROM student WHERE teacher_id IN ( SELECT teacher_id FROM teacher WHERE teacher_name like '牛%' );
这是使用子查询配合IN操作符来过滤数据的一种写法。
是不是比前面的两步操作要简单的多了。
使用子查询过滤数据(EXISTS)
我们还可以使用子查询配合EXISTS关键字来实现上面的需求:
SELECT student_id,student_name FROM student a WHERE EXISTS ( SELECT 1 FROM teacher b WHERE a.teacher_id = b.teacher_id AND b.teacher_name like '牛%' );
EXISTS是存在的意思。从WHERE后面的子查询来看,也就是说,存在一个学生的老师编号,在老师表里,对应的老师姓牛。
那既然有存在的写法,当然也有不存在的写法。
(1)、如何获取除姓牛的老师之外的其他老师教了哪些学生?
SELECT student_id,student_name FROM student a WHERE NOT EXISTS ( SELECT 1 FROM teacher b WHERE a.teacher_id = b.teacher_id AND b.teacher_name like '牛%' );
写起来也很简单,就是在EXISTS前面加上了一个NOT,用来表示否定后面的条件。
本站所有内容均为原创,本站保留所有权利。仅允许非商业用途的转载,但必须注明来源网站、作者、来源链接!否则,由此造成的一切后果,由转载方承担!
干货分享、技术提升、面试笔试、学习交流,欢迎关注公众号:xuesql。QQ学习交流群:209942678。