2012年3月28日星期三

IN与EXISTS,NOT IN与NOT EXISTS的比较

IN与EXISTS,NOT IN与NOT EXISTS的比较



强调下:在含有NULL值的列的时候,就要小心了,not exists与not in在逻辑上是不等价的
--先创建2张表
use master;

if db_id('DbTest') is not null drop database DbTest;

create database DbTest;
go

use DbTest;
go

--创建Customers表
create table Customers
(
custid INT NOT NULL IDENTITY,
companyname NVARCHAR(40) NOT NULL,
country NVARCHAR(15) NOT NULL,
constraint pk_customer primary key(custid)
);
--创建Orders表
CREATE TABLE Orders
(
orderid INT NOT NULL IDENTITY,
custid INT NULL,

CONSTRAINT PK_Orders PRIMARY KEY(orderid),
CONSTRAINT FK_Orders_Customers FOREIGN KEY(custid)
REFERENCES Customers(custid),

);
set identity_insert Customers on;

INSERT INTO Customers(custid, companyname,country)
VALUES(1, N'大众', N'中国');
INSERT INTO Customers(custid, companyname,country)
VALUES(2, N'宝马', N'美国');
INSERT INTO Customers(custid, companyname,country)
VALUES(3, N'奔驰', N'中国');
INSERT INTO Customers(custid, companyname,country)
VALUES(4, N'奇瑞', N'德国');
INSERT INTO Customers(custid, companyname,country)
VALUES(5, N'福特', N'美国');

set identity_insert Customers off;
set identity_insert Orders on;
--custid代表员工号
INSERT INTO Orders(orderid, custid)
VALUES(1,1);
INSERT INTO Orders(orderid, custid)
VALUES(2,2);
INSERT INTO Orders(orderid, custid)
VALUES(3,3);
INSERT INTO Orders(orderid, custid)
VALUES(4,4);
INSERT INTO Orders(orderid, custid)
VALUES(5,5);
--查看表的数据
select custid,companyname,country from Customers;
select orderid,custid from Orders;
--插入数据成功

--咱们回到正题,比较Exists与in,not exists与 not in

--查询来自中国,而且下过订单的所有客户
select custid,companyname
from Customers as C
where country=N'中国'
and exists (select * from Orders as O where O.custid=C.custid);
--返回
--custid companyname
--1 大众
--3 奔驰

--外部查询返回来自中国的客户信息,对于这个客户,exists谓词在Orders表查找是否至少存在一个与外部客户行信息相同的custid订单行

--用IN查询刚刚的需求
select custid,companyname
from Customers as C
where country=N'中国'
and custid in(select custid from Orders);
--结果跟上面的返回一样的值

--下面的知识点我们需要认识到:
--当列表中有NULL时,in实际会产生一个UNKNOWN的结果,例如 a in(d,b,null)的结果是UNKNOWN,而a not in (d,b,null)返回的是not unknowd仍然是unknowd
--而not in与not exists则结果会很不同,例如a in(a,b,null)返回的是TRUE,而a not in(a,b,null)返回的肯定是not true即为false
--有了上面的认识,好继续开工了....
--我们现在向Orders表插入一行数据(6,null)
set identity_insert Orders on;

insert into Orders(orderid,custid) values(6,null);

set identity_insert Orders off;

set identity_insert Customers on;

insert into Customers(custid,companyname,country) values(7,N'雷克萨斯',N'美国');

set identity_insert Customers off;

select * from Orders;
select * from Customers;


--假设现在要返回来自美国且没有订单的客户
select custid,companyname
from Customers as C
where country=N'美国'
and not exists (select * from Orders as O where O.custid=C.custid );
--返回
--custid companyname
--7 雷克萨斯

--我们再用IN方法
select custid,companyname
from Customers as C
where country=N'美国'
and custid not in(select custid from Orders);
--返回的结果为空!!!
--为什么呢??
--因为还记得我们刚插入的一行数据中custid为null么,这就是问题所在
--not in (select custid from Orders)返回的实际是unknown,所以返回结果集为空,除非你显示的规定custid不能为空

--下面是正确的解决方法
select custid,companyname
from Customers as C
where country=N'美国'
and custid not in (select custid from Orders where custid is not null);
--返回
--custid companyname
--7 雷克萨斯

--所以在含有NULL值的列的时候,就要小心了,not exists与not in在逻辑上是不等价的

作者:大蜗牛出处:http://www.cnblogs.com/lixiaofei/本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

TAG:SQL2008 NOT IN NOT EXISTS