开发随笔——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)
(一) 近日和一同学联系,说了我想要做一个网站的打算.她很感兴趣.于是我们协商了下,便觉得一起合作.她写前端,我写后台.因为我对于前端样式设计并不怎么熟悉. (二) 我们决定先做一个 个人博客. 网上 ...
随机推荐
- centos安装Chromium
1. Change root user Shell su - ## OR ## sudo -i 0 1 2 3 4 su - ## OR ## sudo -i 2a. Install NCSU ...
- 关于split与StringTokenizer的理解
关于split与StringTokenizer的理解 一.split 依据匹配给定的正則表達式来拆分此字符串.此方法返回的数组包括此字符串的子字符串,每一个子字符串都由还有一个匹配给定表达式的子 ...
- hadoop日志分析
一.项目要求 本文讨论的日志处理方法中的日志,仅指Web日志.事实上并没有精确的定义,可能包含但不限于各种前端Webserver--apache.lighttpd.nginx.tomcat等产生的用户 ...
- VMware workstation 安装错误提示1021解决方法
Failed to create the requested registry key Key: Installer Error: 1021 解决方法:删除注册表--HKEY_LOCAL_MACHIN ...
- 修ecshop品牌筛选以LOGO图片形式显示
如何实现商品列表页属性筛选区品牌筛选以LOGO形式展示,最模板总结ecshop/'>ecshop教程入下: 1.修改 category.php 文件,将(大概215行) $sql = " ...
- Unity多玩家网络游戏开发教程1章Unity带有网络功能
Unity网络多玩家游戏开发教程第1章Unity自带网络功能 Unity拥有大量的第三方插件.专门提供了对网络功能的支持. 可是.大部分开发人员第一次接触到的还是Unity自带的网络功能.也就是大家常 ...
- 黄聪:Microsoft Enterprise Library 5.0 系列教程(二) Cryptography Application Block (高级)
原文:黄聪:Microsoft Enterprise Library 5.0 系列教程(二) Cryptography Application Block (高级) 本章介绍的是企业库加密应用程序模块 ...
- JSP与ASP.PHP的比較
眼下,最经常使用的三种动态网页语言为:ASP(Active Server Pages).PHP(HyperText Preprocessor)及JSP(Java Server Pages). JSP与 ...
- Android Ant 和 Gradle 打包流程和效率对照
一.Ant 打包:(下载ant.配置环境变量就不说了) 1.进入命令行模式,并切换到项目文件夹.运行例如以下命令为ADT创建的项目加入ant build支持: android update proje ...
- 国庆去学校的国际象棋(Latex)
国庆节去学棋与朋友. 看国外的网站更有趣的事情. 很快打下来. 首先效应: 嘿嘿 代码来了哟: \usepackage[utf8]{inputenc} \usepackage[T1]{fontenc ...