in子查询相关

原文链接(本文与原文存在部分不通):https://blog.csdn.net/weixin_33331978/article/details/113123563

in子查询语法错误,却不影响整个查询的正确性

user表

id name age
1 A 9
2 B 11
3 C 15
4 D 13

blacklist表

id name type
1 B 1
2 C 0
3 D 1

错误流程

目的:查黑名单中年龄大于10的男用户的所有信息
正确语句

select * from user where name in (
	select name from blacklist where type = 1
) and age > 10;

错误语句

SELECT * FROM usr WHERE NAME IN (
	SELECT NAME FROM blacklist WHERE TYPE=1 AND age>10
);

把age条件加在了in查询里,可是黑名单没有age字段。

单独执行子查询报错!
在这里插入图片描述
执行完整语句,返回正确结果
在这里插入图片描述

问题分析

1、EXPLAIN EXTENDED

EXPLAIN EXTENDED 
SELECT * FROM USER WHERE NAME IN (
	SELECT NAME FROM blacklist WHERE TYPE=1 AND age>10
);

在这里插入图片描述
2、SHOW WARNINGS;
在这里插入图片描述
3、分析该语句

Field or reference 'test.USER.age' of SELECT #2 was resolved in SELECT #1
select `test`.`user`.`id` AS `id`,`test`.`user`.`name` AS `name`,`test`.`user`.`age` AS `age` 
from `test`.`user` where <in_optimizer>(`test`.`user`.`name`,<exists>(
		select 1 from `test`.`blacklist` where(
		(`test`.`blacklist`.`type` = 1) and (`test`.`user`.`age` > 10) and (<cache>(`test`.`user`.`name`) = `test`.`blacklist`.`name`)
		)
	)
)

简单来说,数据库优化之后,每个字段都指向了正确的表。

面试回答:一般来说,我会先试一下,explain或者explain extended,然后show warnings


文章对比,我explain之后,show warnings; 没有任何反应。
因此我用的explain extended,但是我的show warnings结果和他的不太一样,它的是结果出来是join,我的并没有。

可以看出,数据库把原来的查询改成了join查询,每个字段都指向了正确的表。

具体问题待确认,估计是版本问题?

in换成exists

如果in里面有语法错误没有暴露的,把in改成exists试一下:

SELECT * FROM USER WHERE EXISTS (
	SELECT NAME FROM blacklist WHERE TYPE = 1 AND age > 10
);

结果:
在这里插入图片描述
结果不对,并且EXISTS返回的是一个布尔值,只要其中的子查询返回行数,where条件即成立。所以,select name 换成select 1也是成立的,即结果和之前的一样。

 select * from user where EXISTS (
	 select 1 from blacklist where type = 1 and age > 10
 );

结果和之前的一样
在这里插入图片描述

分析

EXPLAIN EXTENDED SELECT * FROM USER WHERE EXISTS (SELECT NAME FROM blacklist WHERE TYPE = 1 AND age > 10);
SHOW WARNINGS; 

结果:

Field or reference 'test.user.age' of SELECT #2 was resolved in SELECT #1
select `test`.`user`.`id` AS `id`,`test`.`user`.`name` AS `name`,`test`.`user`.`age` AS `age` 
	from `test`.`user` where exists(
		select `test`.`blacklist`.`name` from `test`.`blacklist` where (
			(`test`.`blacklist`.`type` = 1) and (`test`.`user`.`age` > 10)
	)
)

使用exists,同样优化掉了低级错误。如果想要得到我们预期的数据,需要在exists子查询添加一个条件

select * from user a where EXISTS (
	select 1 from blacklist where type = 1 and name = a.name and age > 10
);

在这里插入图片描述

exists可以看做一个循环

List result = new ArrayList<>();

List user = new ArrayList<>();
for (int i = 0; i < user.size(); i++){
    
    
	if (exists(black.type == 1 && black.name.equals(user.get(i).name)) && user.get(i).age > 10){
    
    
		result.add(user.get(i));
	}
}

N和Exists的区别

Exists:先执行外部查询语句,然后在执行子查询,子查询中它每次都会去执行数据库的查询,执行次数等于外查询的数据数量。

In:先查询 in()子查询的数据(1次),并且将数据放进内存里(不需要多次查询),然后外部查询的表再根据查询的结果进行查询过滤,最后返回结果。

In 是把外表和内表作hash 连接,而exists是对外表作loop循环,每次loop循环再对内表进行查询。


总结

in子句语法错误,可能不会影响整个语句的执行。

其他

MySQL数据库中有一个explain 命令,其主要功能是用来分析select 语句的运行效果,例如explain可以获得select语句使用的索引情况、排序的情况等等。

explain 的extended 扩展能够在原本explain的基础上额外的提供一些查询优化的信息,这些信息可以通过MySQL的show warnings命令得到。

”从MySQL explain extend的输出中,我们可以看到sql的执行方式,对于分析sql还是很有帮助的”。

猜你喜欢

转载自blog.csdn.net/root_zhb/article/details/115028656