SQL server 中not in 和 no exists的区别
最近在看数据库.看到not in 和 no exists 时,我被弄糊涂了.下面是我的测试.
TestFirstTable
1Testone 123456
2TestTwo 1111111
3testthr 12231231
4testfour 22324
5testfour 22324
6testfour 22324
TestTwoTable
1testone 123231
2testone 123231
4testone 123231
6testone 123231
8testone 123231
我写了以下五个查询语句:
1)
select * from TestFristTable as a where a.TestID not in(select TestID from TestTwo)
2)
select * from TestFristTable where not exists(select TestTwo.TestID from TestTwo,TestFristTable where TestTwo.TestID=TestFristTable.TestID)
3)
select TestTwo.TestID from TestTwo,TestFristTable where TestTwo.TestID=TestFristTable.TestID
4)
select * from TestFristTable where not exists(select TestID from TestTwo where TestTwo.TestID=TestFristtable.TestID)
5)
select TestID from TestTwo where TestTwo.TestID=TestFristtable.TestID
第5个在执行时会报错,可以选中前四个一起执行得到的结果是:
1)
3testthr 12231231
5testfour 22324
2)
空
3)
1
2
4
6
4)
3testthr 12231231
5testfour 22324
这就出现问题了.
第二个语句的查询结果是空,但是子查询语句的结果却有值 .
3)
1
2
4
6
更奇怪的是第4、5两句。第5句是第4句的子查询。当执行第五句时回报错,但是第4句却可以查找出我想要的结果
4)
3testthr 12231231
5testfour 22324
为什么呢?
为什么2、3,子查询语句有值,但整个语句没值 。4、5 子查询语句单独执行都会报错,为什么整个查询语句却可以查出结果?
[解决办法]
几乎一样.不过no exists 比not in 教快.
另:如果存在多个字段的比较,则只能用not exists
例如查询a表ID不在B表的id
select a.* from a where id not in (select id from b)
select a.* from a where not exists(select 1 from b where b.id = a.id)
例如查询a表ID不在B表的id1+id2
select a.* from a where not exists(select 1 from b where b.id1 = a.id1 and b.id2 = a.id2)
[解决办法]
我写了以下五个查询语句:
1)
select * from TestFristTable as a where a.TestID not in(select TestID from TestTwo)
====
正确
2)
select * from TestFristTable where not exists(select TestTwo.TestID from TestTwo,TestFristTable where TestTwo.TestID=TestFristTable.TestID)
====
语法正确,逻辑错误。
红色部分是单独的语句,执行总是有结果,所以not exists总是False,所以结果是空。
3)
select TestTwo.TestID from TestTwo,TestFristTable where TestTwo.TestID=TestFristTable.TestID
====
正确。
这是老式的JOIN语法,建议用INNER JOIN代替。
4)
select * from TestFristTable where not exists(select TestID from TestTwo where TestTwo.TestID=TestFristtable.TestID)
====
正确。逻辑上与1)等价,当TestTwo.TestID不包含NULL值时。
5)
select TestID from TestTwo where TestTwo.TestID=TestFristtable.TestID
====
语法错误。
4)是相关子查询,子查询部分不能作为单独语句执行。
[解决办法]
其实LZ搞清楚in和exists的区别就大概明白了IN 确定给定的值是否与子查询或列表中的值相匹配。 EXISTS 指定一个子查询,检测行的存在。 比较使用 EXISTS 和 IN 的查询 exists()后面的子查询被称做相关子查询 他是不返回列表的值的.只是返回一个ture或false的结果,其运行方式是先运行主查询一次 再去子查询里查询与其对应的结果 如果是ture则输出,反之则不输出.再根据主查询中的每一行去子查询里去查询. in()后面的子查询 是返回结果集的,换句话说执行次序和exists()不一样.子查询先产生结果集,然后主查询再去结果集里去找符合要求的字段列表去.符合要求的输出,反之则不输出.
[解决办法]
逻辑要求:查询T1表中不在T2表的记录。
方法1:SELECT * FROM T1 WHERE T1.ID NOT IN (SELECT T2.ID FROM T2)
方法1.1:SELECT * FROM T1 WHERE T1.ID NOT IN (SELECT T2.ID FROM T2 WHERE T2.ID IS NOT NULL)
====
以上两个都是不相关子查询(独立子查询),子查询部分可以作为单独语句执行。
方法1和方法1.1的区别在于一点细微的逻辑差异(与NULL和三值逻辑有关),当T2.ID列包含NULL时,查询结果会有区别。
参看:http://topic.csdn.net/u/20100826/18/7b81012a-b5c4-48b1-b5d1-40a92f3e0388.html
方法2:SELECT * FROM T1 WHERE NOT EXISTS (SELECT * FROM T2 WHERE T2.ID = T1.ID)
方法2的常见错误写法:SELECT * FROM T1 WHERE NOT EXISTS (SELECT * FROM T2,T1 WHERE T2.ID = T1.ID)
====
以上两个都是相关子查询(非独立子查询),子查询部分需要引用外层语句的字段,不可以作为单独语句执行。
以上两个语句中,子查询中的T1.ID引用的是红色的表名。
方法2是实现该逻辑需求的最优方案,但逻辑上比方法1难懂一点。
但其实只要搞清楚了方法2和方法2的常见错误写法的区别,EXISTS/NOT EXISTS就算是完全弄懂了。
[解决办法]
3)select TestTwo.TestID from TestTwo,TestFristTable where TestTwo.TestID=TestFristTable.TestID--这里查找不在testtwo ,可以用left joinselect TestFristTable.TestID from TestFristTable left join TestTwo on TestTwo.TestID=TestFristTable.TestID where TestTwo.TestID is null--最主要where TestTwo.TestID is null2)在exist子句中,你又再一次使用TestFristTable,此表与外层的TestFristTable无关系了,所以改写就成了 4)第四个例子!