开发随笔——NOT IN vs NOT EXISTS
之前在论坛中见到一个针对in/exists的讨论,原帖懒得找了,这里介绍一下最近的学习小结:
NOT IN和NOT EIXTS在对允许为null的列查询时会有一定的风险。特别是NOT IN,如果子查询包含了最少一个NULL,会出现非预期的结果。下面做一个演示。
IF OBJECT_ID('ShipmentItems', 'U') IS NOT NULL
DROP TABLE dbo.ShipmentItems;
GO
CREATE TABLE dbo.ShipmentItems
(
ShipmentBarcode VARCHAR(30) NOT NULL ,
Description VARCHAR(100) NULL ,
Barcode VARCHAR(30) NOT NULL
);
GO
INSERT INTO dbo.ShipmentItems
( ShipmentBarcode ,
Barcode ,
Description
)
SELECT '123456' ,
'1010203' ,
'Some cool widget'
UNION ALL
SELECT '123654' ,
'1010203' ,
'Some cool widget'
UNION ALL
SELECT '123654' ,
'1010204' ,
'Some cool stuff for some gadget';
GO
-- retrieve all the items from shipment 123654
-- that are not shipped in shipment 123456
SELECT Barcode
FROM dbo.ShipmentItems
WHERE ShipmentBarcode = '123654'
AND Barcode NOT IN ( SELECT Barcode
FROM dbo.ShipmentItems
WHERE ShipmentBarcode = '123456' );
/*
Barcode
------------------------------
1010204
*/
可以看出得到了期待结果。下面看看修改表结构,允许列为null的情况:
ALTER TABLE dbo.ShipmentItems
ALTER COLUMN Barcode VARCHAR(30) NULL;
INSERT INTO dbo.ShipmentItems
( ShipmentBarcode ,
Barcode ,
Description
)
SELECT '123456' ,
NULL ,
'Users manual for some gadget';
GO
SELECT Barcode
FROM dbo.ShipmentItems
WHERE ShipmentBarcode = '123654'
AND Barcode NOT IN ( SELECT Barcode
FROM dbo.ShipmentItems
WHERE ShipmentBarcode = '123456' );
/*
Barcode
------------------------------
*/
很多人会觉得这是一个bug,有时候能查出数据,有时候却不能。但是实际上不是bug,当NOT IN子句返回最少一个NULL时,查询会返回空,下面的语句能更好地说明这个想法:
SELECT CASE WHEN 1 NOT IN ( 2, 3 ) THEN 'True'
ELSE 'Unknown or False'
END ,
CASE WHEN 1 NOT IN ( 2, 3, NULL ) THEN 'True'
ELSE 'Unknown or False'
END;
/*
---- ----------------
True Unknown or False
*/
实际上,由于IN的本质是OR操作,所以:
SELECT CASE WHEN 1 IN ( 1, 2, NULL ) THEN 'True'
ELSE 'Unknown or False'
END ;
中,1 in 1,也就是为TRUE,所以返回true,这个语句的逻辑实际上是:
SELECT CASE WHEN ( 1 = 1 )
OR ( 1 = 2 )
OR ( 1 = NULL ) THEN 'True'
ELSE 'Unknown or False'
END ;
当使用NOT IN 时,如下面的语句:
SELECT CASE WHEN 1 NOT IN ( 1, 2, NULL ) THEN 'True'
ELSE 'Unknown or False'
END ;
会转变成:
SELECT CASE WHEN NOT ( ( 1 = 1 )
OR ( 1 = 2 )
OR ( 1 = NULL )
) THEN 'True'
ELSE 'Unknown or False' END ;
根据离散数学的概念,可以转换为:
SELECT CASE WHEN ( ( 1 <> 1 )
AND ( 1 <> 2 )
AND ( 1 <> NULL )
) THEN 'True'
ELSE 'Unknown or False'
END ;
谓词有短路特性,即在AND条件中,只要有一个条件为false,整个条件都为false,而1<>1是为false,所以后面的也不需要判断了,直接返回else部分。即使是1<>null,根据集合论的特性,NULL和实际数据的对比总是返回unknown,所以也是为false。如果你非要用NOT IN ,请确保子查询永远不会有NULL返回。或者需要额外处理去除NULL,比如:
SELECT Barcode
FROM dbo.ShipmentItems
WHERE ShipmentBarcode = '123654'
AND Barcode NOT IN ( SELECT Barcode
FROM dbo.ShipmentItems
WHERE ShipmentBarcode = '123456'
AND Barcode IS NOT NULL ) ;
还有一种方法就是改写语句,用NOT EXISTS来等价替换:
SELECT i.Barcode
FROM dbo.ShipmentItems AS i
WHERE i.ShipmentBarcode = '123654'
AND NOT EXISTS ( SELECT *
FROM dbo.ShipmentItems AS i1
WHERE i1.ShipmentBarcode = '123456'
AND i1.Barcode = i.Barcode );
/*
Barcode
------------------------------
1010204
*/
另外,基于SARG要求,一般不建议用NOT IN/NOT EXISTS这种反向扫描,避免影响性能。还有一个选择使用IN/EXISTS的要点,就是多列匹配的问题,在T-SQL中,多列同时匹配要用EXISTS,而单列匹配可以用EXISTS/IN。可能可以用其他写法来实现IN的多列匹配,但是一般我个人会选择使用EXISTS来匹配多列。
原文出自:CSDN博客:黄钊吉的博客
开发随笔——NOT IN vs NOT EXISTS的更多相关文章
- Kinect开发随笔①——红外扫描仪(Kinect 数据源)
来源于 MVA 的 快速入门:Kinect for Windows v2 开发 的学习随笔 具体内容为上图所示章节内容 章节内全部代码:GitHub地址点我(链接失效,待补档) <Page &l ...
- UWP开发随笔——使用SQLite数据库
摘要 大多数的app都需要数据存储,在数据存储这方面,强大的windows把app数据分为两种:settings和files,并提供了十分简洁的api,让开发者能够轻松使用.但是在有些场景下,app的 ...
- 初学安卓开发随笔之 Intent 用法
首先,对于安卓开发,目前世界上流行的是使用的是Android studio 2.0 .(hh 学着来呗 书上说用这个,,) 今后就定一个计划 每天更新一个Android 随笔,增强一下自控力吧!!! ...
- FPGA开发随笔汇总
点击标题即可进入相关随笔. DE-SOC开发板VrilogHDL开发相关部分: (本过程需要Verilog HDL 的基本语言基础) 1.FPGA的发展史及FPGA 的基础架构 2.首先看一下友晶DE ...
- cefSharp 开发随笔
最近用cefSharp开发一点简单的东西.记录一点随笔,不定时更新. 1.用nuget安装完之后,架构要选择x86或者x64,否则编译会报错(截止到Chrome 55版本) 2.向Chrome注册C# ...
- ActiveReport系列报表开发随笔收集
转自:博客园 http://www.cnblogs.com/dahuzizyd/archive/2007/04/11/ActiveReport_All.html 使用ActiveReport for ...
- 如何提高码农产量,基于ASP.NET MVC的敏捷开发框架之移动端开发随笔二
前言 在前一篇文章中我已经做过开篇,接下来的随笔会详细讲一下我们的开发框架是如何实现的,专业的事由专业的人来讲,以后就由我们的高级码农小李英文名查尔斯和他的师父厂长(因为姓陈,酷爱摄影,我们的文艺片都 ...
- com.panie 项目开发随笔(NoF)_环境搭建(2016.12.29)
(一) 最近做的框架一直在 spring + springmvc + mybatis 的基础上,使用框架的好处自然是 简化了自己的开发工作,定义好大的结构体系后就在里面套用方法了! 可是框架的毛病同样 ...
- com.panie 项目开发随笔_前后端框架考虑(2016.12.8)
(一) 近日和一同学联系,说了我想要做一个网站的打算.她很感兴趣.于是我们协商了下,便觉得一起合作.她写前端,我写后台.因为我对于前端样式设计并不怎么熟悉. (二) 我们决定先做一个 个人博客. 网上 ...
随机推荐
- Jquery利用ajax调用asp.net webservice的各种数据类型(总结篇)
原文:Jquery利用ajax调用asp.net webservice的各种数据类型(总结篇) 老话说的好:好记心不如烂笔头! 本着这原则,我把最近工作中遇到的jquery利用ajax调用web服务的 ...
- matlab 2014a 改为英文版本号
1. 在 Matlab 的安装目录以下找到例如以下的路径,X:\MATLAB\R2014a\java\jar,当中 X 为安装盘符,这个不用过多解释了,然后找到目录 zh_CN.此目录就是中文界面的语 ...
- POJ 3630 Phone List Trie题解
Trie的应用题目. 本题有两个难点了: 1 动态建立Trie会超时,须要静态建立数组,然后构造树 2 推断的时候注意两种情况: 1) Tire树有133,然后插入13333556的时候.2)插入顺序 ...
- html弹窗,与弹出对话框
弹出对话框 <script type="text/JavaScript"> <!-- alert("Good Morning!"); //al ...
- Windows Phone开发(3):棋子未动,先观全局
原文:Windows Phone开发(3):棋子未动,先观全局 在进行WP开发之前,与其它开发技术一样,我们需要简单了解一个WP应用序的生命周期,我们不一定要深入了解,但至少要知道在应用程序生命周期内 ...
- POJ 3450 Corporate Identity KMP解决问题的方法
这个问题,需要一组字符串求最长公共子,其实灵活运用KMP高速寻求最长前缀. 请注意,意大利愿父亲:按照输出词典的顺序的规定. 另外要提醒的是:它也被用来KMP为了解决这个问题,但是很多人认为KMP使用 ...
- 一起学习android图片四舍五入图片集资源 (28)
效果图: 參看下面代码: public class MainActivity extends Activity { private ImageView imageView1; private Imag ...
- Oracle Hints详细解释
特别介绍给大家Oracle Hints之前,让我们知道下Oracle Hints什么,然后好Oracle Hints,我们希望实际.基于成本的优化器是很聪明,在大多数情况下,将选择正确的优化,减少DB ...
- sql中 in 、not in 、exists、not exists 使用方法和区别
% 的一类. NOT IN:通过 NOT IN keyword引入的子查询也返回一列零值或很多其它值. 以下查询查找没有出版过商业书籍的出版商的名称. SELECT pub_name FROM pub ...
- NTP方式保证以时间戳同步可靠性
数据库同步的方式有设置标志位同步方式.以时间戳同步的方式,对于一对一的同步这两种方式都满足,可是对于一对多的同步,则仅仅能选择时间戳的同步方式了.可是已时间戳同步的方式的一个问题是怎样可靠的保证数据能 ...