今天在学习sql语句时,遇到关于exsits的用法,下面是题目:
表架构
Student(S#,Sname,Sage,Ssex) 学生表
Course(C#,Cname,T#)
课程表
SC(S#,C#,score) 成绩表
Teacher(T#,Tname) 教师表
问题:
查询学过“001”并且也学过编号“002”课程的同学的学号、姓名:
即执行主句查询前,先查询是否子句是否为真,若存在学过002课程的学生,再执行查询学过001的,
此时查询出来的结果,就符合既学过001又学过002。
select Student.`S#`,Student.Sname from Student,SC where Student.`S#`=SC.`S#` and SC.`C#`=‘001‘and exists( Select * from SC as SC_2 where SC_2.`S#`=SC.`S#` and SC_2.`C#`=‘002‘);
由此对比in和exsits的用法:
exsits:
exsits子句返回的并非查询结果,而是布尔值,TRUE或者FALSE,exists对外表用loop逐条查询,
每次查询都会查看exists的条件语句,当 exists里的条件语句,能够返回记录行时(无论记录行是的多少,只要能返回),条件就为真,
返回当前loop到的这条记录,反之如果exists里的条件语句不能返回记录行,则当前loop到的这条记录被丢弃,exists的条件就像一个bool条件,
当能返回结果集则为true,不能返回结果集则为 false。
In:
in查询相当于多个or条件的叠加,这个比较好理解,比如下面的查询:
select * from user where userId in (1, 2, 3);
等效于
select * from user where userId = 1 or userId = 2 or userId = 3;
not in与in相反,如下
select * from user where userId not in (1, 2, 3);
等效于
select * from user where userId != 1 and userId != 2 and userId != 3;
总的来说,in查询就是先将子查询条件的记录全都查出来,假设结果集为B,共有m条记录,然后在将子查询条件的结果集分解成m个,再进行m次查询
值得一提的是,in查询的子条件返回结果必须只有一个字段,例如
select * from user where userId in (select id from B);
而不能是
select * from user where userId in (select id, age from B);
而exists就没有这个限制
性能方面对比:
1: select * from A where exists (select * from B where B.id = A.id);
2: select * from A where A.id in (select id from B);
查询1.可以转化以下伪代码,便于理解
for ($i = 0; $i < count(A); $i++) {
$a = get_record(A, $i); #从A表逐条获取记录
if (B.id = $a[id]) #如果子条件成立
$result[] = $a;
}
return $result;
大概就是这么个意思,其实可以看到,查询1主要是用到了B表的索引,A表如何对查询的效率影响应该不大
假设B表的所有id为1,2,3,查询2可以转换为
select * from A where A.id = 1 or A.id = 2 or A.id = 3;
这个好理解了,这里主要是用到了A的索引,B表如何对查询影响不大。