再举个例子, 比如查询比每个班级中比平均年龄大的学生姓名信息:
SELECT name FROM student as s1 WHERE age > (SELECT AVG(age) FROM student as s2 where s1.class_id = s2.class_id)这里根据每名同学的班级信息,查找出对应班级的平均年龄,然后做判断。子查询每次执行时,都需要根据外部的查询然后进行计算。这样的子查询就是关联子查询。
EXISTS 子查询在关联子查询中,常会和 EXISTS 一起使用。用来判断条件是否满足,满足的话为 True,不满足为 False。
比如查询参加过学校活动的学生名称:
SELECT NAME FROM student as s where \ EXISTS(SELECT stu_id FROM student_activities as sa where sa.stu_id=s.id)同样 NOT EXISTS 就是不存在的意思,满足为 FALSE , 不满足为 True.
比如查询没有参加过学校活动的学生名称:
SELECT NAME FROM student as s where \ NOT EXISTS(SELECT stu_id FROM student_activities as sa where sa.stu_id=s.id) 集合比较子查询可以在子查询中,使用集合操作符,来比较结果。
还是上面查询参加学校活动的学生名字的子查询, 同样可以使用 IN:
SELECT name FROM student WHERE id IN (SELECT stu_id FROM student_activities) EXISTS 和 IN 的区别既然 EXISTS 和 IN 都能实现相同的功能,那么他们之间的区别是什么?
现在假设我们有表 A 和 表 B,其中 A,B 都有字段 cc,并对 cc 建立了 b+ 索引,其中 A 表 n 条记录,B 表 m 条索引。
将其模式抽象为:
SELECT * FROM A WHERE cc IN (SELECT cc FROM B) SELECT * FROM A WHERE EXIST (SELECT cc FROM B WHERE B.cc=A.cc)对于 EXISTS 来说,会先对外表进行逐条循环,每次拿到外表的结果后,带入子查询的内表中,去判断该值是否存在。
伪代码类似于下面:
for i in A for j in B if j.cc == i.cc: return result首先先看外表 A,每一条都需要遍历到,所以需要 n 次。内表 B,在查询时由于使用索引进而查询效率变成 log(m) B+ 的树高,而不是 m。
进而总效率:n * log(m)
所以对于 A 表的数量明显小于 B 时,推荐使用 EXISTS 查询。
再看 IN ,会先对内表 B 进行查询,然后用外表 A 进行判断,伪代码如下:
for i in B for j in A if j.cc == i.cc: return result由于需要首先将内表所有数据查出,所以需要的次数就是 m. 再看外表 A ,由于使用了 cc 索引,可将 n 简化至 log(n), 也就是 m * log(n).
所以对于 A 表的数据明显大于 B 表时,推荐使用 IN 查询。
总结一下对于 IN 和 EXISTS时,采用小表驱动大表的原则。
这里再扩展下 NOT EXISTS 和 NOT IN 的区别:
SELECT * FROM A WHERE cc NOT IN (SELECT cc FROM B) SELECT * FROM A WHERE NOT EXIST (SELECT cc FROM B WHERE B.cc=A.cc)对于 NOT EXITS 来说,和 EXISTS 一样,对于内表可以使用 cc 的索引。适用于 A 表小于 B 表的情况。
但对于 NOT IN 来说,和 IN 就有区别了,由于 cc 设置了索引 cc IN (1, 2, 3) 可以转换成 WHERE cc=1 OR cc=2 OR cc=3 , 是可以正常走 cc 索引的。但对于 NOT IN 也就是转化为 cc!=1 OR cc!=2 OR cc!=3 这时由于是不等号查询,是无法走索引的,进而全表扫描。
也就是说,在设置索引的情况下 NOT EXISTS 比 NOT IN 的效率高。
但对于没有索引的情况,IN 和 OR 是不同的:
一、操作不同 1、in:in是把父查询表和子查询表作hash连接。 2、or:or是对父查询表作loop循环,每次loop循环再对子查询表进行查询。 二、适用场景不同 1、in:in适合用于子查询表数据比父查询表数据多的情况。 2、or:or适合用于子查询表数据比父查询表数据少的情况。 三、效率不同 1、in:在没有索引的情况下,随着in后面的数据量越多,in的执行效率不会有太大的下降。 2、or:在没有索引的情况下,随着or后面的数据量越多,or的执行效率会有明显的下降。 总结这篇文章中主要归纳了一些 SQL 的基础知识:
在使用 SELECT 查询时,通过显式指定列名,来减少 IO 的传输,从而提高效率。
并且需要注意 SELECT 的查询过程会从 FROM 后开始到 LIMIT 结束,理解了整体的流程,可以让我们更好的组织 SQL.
之后详细介绍了 WHERE 进行过滤的操作符和常用的函数,这里要注意在比较时间时要使用 DATE 函数,以及如何对数据进行分组和过滤。
最后着重介绍了子查询,IN 和 EXISTS 的适用场景。