首先我要感谢aa和Liu Xing帮我发现了我日志中的错误。之前比较粗心,把3条SQL语句写成一样的了,对于给读者造成的麻烦,我深表抱歉。
今天我把原文做了修订,为了对得起读者对我的关注,我重新深入的研究了这个问题,在后面,我会把来龙去脉写清楚。
问题:
语句1
:
Select
*
from
table1 A
where
A.col1
not
in
(
select
col1
from
table2 B )
转载注明出处:http://x-
spirit.iteye.com/、http:
//www.blogjava.net/zhangwei217245/
如果这样,本来应该有一条数据,结果没有。
如果我改写成这样:
语句2
:
select
*
from
table1 A
where
not
exists
(
SELECT
*
FROM
table2 B
where
B.col1
=
A.col1)
结果就正确,有一条数据显示。
转载注明出处:http://x-
spirit.iteye.com/、http:
//www.blogjava.net/zhangwei217245/
经过一番搜索,原以为是子查询结果集太大的原因。
后来有网上强人指点:子查询里面有空集。即子查询的结果集里面有NULL的结果。
把查询语句修改成:
语句3
:
Select
*
from
table1 A
where
A.col1
not
in
(
select
col1
from
table2 B
where
B.col1
is
not
null
)
果然就查出来了。而且一点不差。。。厉害阿~~~
下面是针对本文题的分析:
1。 首先来说说Oracle中的NULL。
Oracle中的NULL代表的是无意义,或者没有值。将NULL和其他的值进行逻辑运算,运算过程中,NULL的表现更象是FALSE。
下面请看真值表:
|
AND NULL
|
OR NULL |
TRUE |
NULL |
TRUE |
FALSE |
FALSE |
NULL |
NULL |
NULL
|
NULL |
另外,NULL和其他的值进行比较或者算术运算(<、>、=、!=、+、-、*、/),结果仍是NULL。
如果想要判定某个值是否为NULL,可以用IS NULL或者IS NOT NULL。
2. 再来说说Oracle中的IN。
in是一个成员条件, 对于给定的一个集合或者子查询,它会比较每一个成员值。
IN功能上相当于 =ANY 的操作,而NOT IN 功能上相当于 !=ALL 的操作。
IN在逻辑上实际上就是对给定的成员集合或者子查询结果集进行逐条的判定,例如:
SELECT
*
FROM
table1 A
WHERE
A.col1
in
(
20
,
50
,
NULL
);
实际上就是执行了
SELECT
*
FROM
table1 A
WHERE
A.col1
=
20
OR
A.col1
=
50
OR
A.col1
=
NULL
;
这样,根据NULL的运算特点和真值表,我们可以看出,上边这个WHERE
字句可以被简化(如果返回NULL则无结果集返回,这一点和FALSE是一样的)为
WHERE
A.col1
=
20
OR
A.col1
=
50
也就是说,如果你的table1中真的存在含有NULL值的col1列,则执行该语句,无法查询出那些值为null的记录。
再来看看NOT IN。根据逻辑运算关系,我们知道,NOT (X=Y OR N=M) 等价于 X!=Y AND N!=M,那么:
SELECT
*
FROM
table1 A
WHERE
A.col1
not
in
(
20
,
50
,
NULL
)
等价于
SELECT
*
FROM
table1 A
WHERE
A.col1
!=
20
AND
A.col1
!=
50
AND
A.col1
!=
NULL
根据NULL的运算特性和真值表,该语句无论前两个判定条件是否为真,其结果一定是NULL或者FALSE。故绝对没有任何记录可以返回。
这就是为什么语句1
查不到应有结果的原因。当然,如果你用NOT IN的时候,预先在子查询里把NULL去掉的话,那就没问题了,例如语句3
。
有些童鞋可能要问了:那如果我想把A表里面那些和B表一样col1列的值一样的记录都查出来,即便A、B两表里面的col1列都包括值为NULL的记录的
话,用这一条语句就没办法了吗?
我只能很遗憾的告诉你,如果你想在WHERE后面单纯用IN 似乎不太可能了,当然,你可以在外部的查询语句中将NULL条件并列进去,例如:
SELECT
*
FROM
table1 A
WHERE
A.col1
in
(
SELECT
B.col1
FROM
table2 B)
OR
A.col1
IS
NULL
;
转载注明出处:http://x-
spirit.iteye.com/、http:
//www.blogjava.net/zhangwei217245/
3. 最后谈谈EXISTS。
有人说EXISTS的性能比IN要好。但这是很片面的。我们来看看EXISTS的执行过程:
select
*
from
t1
where
exists
(
select
*
from
t2
where
t2.col1
=
t1.col1 )
相当于:
for
x
in
(
select
*
from
t1 )
loop
if
(
exists
(
select
*
from
t2
where
t2.col1
=
x.col1 )
then
OUTPUT THE RECORD in x
end
if
end
loop
转载注明出处:http://x-
spirit.iteye.com/、http:
//www.blogjava.net/zhangwei217245/
也就是说,EXISTS语句实际上是通过循环外部查询的结果集,来过滤出符合子查询标准的结果集。于是外部查询的结果集数量对该语句执行性能影响最大,故
如果外部查询的结果集数量庞大,用EXISTS语句的性能也不一定就会好很多。
转载注明出处:http://x-
spirit.iteye.com/、http:
//www.blogjava.net/zhangwei217245/
当然,有人说NOT IN是对外部查询和子查询都做了全表扫描,如果有索引的话,还用不上索引,但是NOT
EXISTS是做连接查询,所以,如果连接查询的两列都做了索引,性能会有一定的提升。
当然至于实际的查询效率,我想还是具体情况具体分析吧。
那么我们不妨来分析一下语句2为什么能够的到正确的结果吧:
语句2是这样的:
select
*
from
table1 A
where
not
exists
(
SELECT
B.col1
FROM
table2 B
where
B.col1
=
A.col1)
实际上是这样的执行过程:
for
x
in
(
select
*
from
table1 A )
loop
if
(not
exists
(
select
*
from
table2 B
where
B.col1
=
x.col1 )
then
OUTPUT THE RECORD in x
end
if
end
loop
转载注明出处:http://x-
spirit.iteye.com/、http:
//www.blogjava.net/zhangwei217245/
由于表A中不包含NULL的记录,所以,遍历完表A,也只能挑出表A中独有的记录。
这就是为什么语句2
能够完成语句3
的任务的原因。
但如果表A中存在NULL记录而表B中不存在呢?
这个问题请大家自己分析吧。哈哈。有答案了可以给我留言哦。
答案:A表中的NULL也会被查出来。因为select * from
table2 B where B.col1 = NULL不返回结果,故
not exists ( select * from table2 B where B.col1 = x.col1 )的值为真。
转载注明出处:http://x-
spirit.iteye.com/、http:
//www.blogjava.net/zhangwei217245/
以上SQL运行结果在MySQL和Oracle上都已经通过。
分享到:
相关推荐
- **推荐方案**:改用NOT EXISTS或外连接加判断为空的方式替换NOT IN。 ##### 3. LIKE操作符 - **使用技巧**:LIKE操作符支持通配符查询,但使用不当会影响性能。例如,“%5400%”不会使用索引;而“X5400%”会...
在描述中提到的符号和操作符,例如`+`、`-`、`*`、`/`用于基本的数学运算,`IS NULL`和`IS NOT NULL`用于检查值是否存在,`BETWEEN`、`NOT BETWEEN`用于区间判断,`IN`、`NOT IN`、`ANY`、`SOME`、`ALL`用于集合比较...
### Oracle SQL语句优化策略详解 #### 操作符优化概览 在Oracle数据库环境中,SQL语句的优化是提升查询效率、减少系统资源消耗的关键环节。通过对特定操作符的合理运用,可以显著改善数据检索的速度与准确性。本文...
### Oracle查询优化详解 在数据库管理与开发领域,Oracle数据库因其强大的功能和广泛的应用而备受青睐。然而,随着数据量的急剧增长,如何提高查询效率成为了一项关键技能。本文将深入探讨Oracle查询优化的几个核心...
根据提供的文件内容,可以看出文档主要涉及的是Oracle SQL的基础语法与函数使用详解。下面将对文档中的各个知识点进行详细的解释和扩展。 ### Oracle SQL基础语法与函数详解 #### 1. 基本运算符 在Oracle SQL中,...
在WHERE子句中使用`IS NULL`或`IS NOT NULL`会导致Oracle优化器无法利用索引进行优化,因为NULL值并不参与索引排序。为了充分利用索引,应避免在WHERE子句中使用这类条件,除非确实需要检查NULL值的存在。 ##### ...
### Oracle 子查询详解 #### 引言 在数据库查询语言SQL中,子查询是一种强大的功能,它允许在一个查询语句内部嵌套另一个查询语句。这种能力极大地扩展了SQL的表达力,使得复杂的业务逻辑可以通过简洁的SQL语句来...
22. NULL和DUAL详解讨论了Oracle中的空值概念,以及特殊的虚拟表DUAL的用途。 23. 时间、数字、字符格式详解,涉及格式化和解析不同数据类型时使用的各种格式。 24. Oracle字符集问题讨论了字符编码和字符集对...
### Oracle SQL优化详解 #### 一、SQL语句编写注意事项 **1. ISNULL与ISNOTNULL** 在WHERE子句中使用`IS NULL`或`IS NOT NULL`时,Oracle优化器通常不会利用索引进行搜索。这是因为`IS NULL`和`IS NOT NULL`检查的...
### Oracle到SQL Server存储过程语法转换详解 在数据库迁移项目中,从Oracle迁移到SQL Server是一种常见的场景。本文旨在提供一份详细的指南,帮助开发者更好地理解这两种数据库系统在存储过程方面的语法差异,并...
- **原因**: Oracle优化器认为`IS NULL`和`IS NOT NULL`条件下的数据分布不可预测,因此不使用索引。 - **解决方案**: 避免在WHERE子句中使用`IS NULL`和`IS NOT NULL`,转而使用具体的值或范围查询。 - 示例: ```...
- `IN`、`NOT IN`、`EXISTS`、`NOT EXISTS` - **示例**: - `SELECT * FROM orders WHERE order_id IN (100, 200, 300)`:此查询将返回订单ID为100、200或300的所有订单记录。 ##### 3. **范围运算符** - `...
在子查询中,使用EXISTS(NOT EXISTS)通常比使用IN(NOT IN)更为高效,因为它只需要判断是否存在满足条件的记录即可,而不需要返回实际的数据。 #### 十七、NOT EXIST与NOT IN的区别 NOT IN在某些情况下可能无法...
### ORACLE高效SQL书写规范详解 #### 一、书写格式规范 **1-1、大小文字及空格的统一** 为了提高SQL语句的可读性和执行效率,建议使用统一的大写或小写来书写SQL语句,并且避免不必要的空格。在ORACLE中,表名、...
与`IN`子查询不同的是,`EXISTS`子查询不关心子查询返回的具体值,只关心是否有结果返回。这使得`EXISTS`子查询在性能上优于`IN`子查询,尤其是在子查询返回多条记录的情况下。 #### 五、应用场景 - **数据同步**...
### Oracle数据库增删改查练习知识点详解 #### 一、建表 1. **创建学生表** (`student`) - **表结构** ```sql CREATE TABLE student ( SNO VARCHAR2(10), SNAME VARCHAR2(10), SAGE DATE, SSEX VARCHAR2(10...
`IN`、`NOT IN`、`EXISTS`、`NOT EXISTS` - **含义**:用于比较一个值是否存在于另一个查询结果集中。 - **示例**: - `SELECT * FROM table1 WHERE id IN (SELECT id FROM table2)`:选择`table1`中id出现在`...
### Oracle优化方法详解 在IT行业中,Oracle数据库作为企业级数据管理的重要工具之一,其性能优化一直是DBA和开发人员关注的重点。本文将基于提供的文件信息,深入探讨Oracle数据库优化的关键知识点,帮助大家提高...