SQL 语句中关于 NULL 的那些坑
问题描述
今天在跟进公司内部测试平台线上问题的时候,发现一个忽略已久的问题。
为了简化问题描述,将其进行了抽象。
有一张数据表qms_branch,里面包含了一批形式如下所示的数据:
| id | name | types |
|---|---|---|
| 1 | dashboard_trunk | dashboard |
| 2 | monkey_trunk | monkey |
| 3 | dashboard_projects_10_9_9 | dashboard |
| 4 | performance_trunk | |
| 5 | performance_projects_10_9_8 | performance |
在系统的某个页面中,需要展示出所有dashboard类型以外的分支,于是就采用如下方式进行查询(Rails)。
branches = Qms::Branch.where("types!='dashboard'")
这个方式有问题么?
之前我是觉得没什么问题。但是在代码上线后,实际使用时发现部分分支没有加载出来,这就包括了performance_trunk分支。
然后就是问题定位,到MySQL的控制台采用SQL语句进行查询:
SELECT * FROM qms_branch WHERE types != 'dashboard'
发现在查询结果中的确没有包含performance_trunk分支。
这是什么原因呢?为什么在第4条数据中,types属性的值明明就不是dashboard,但是采用types!='dashboard'就无法查询得到结果呢?
原因追溯
查看数据表qms_branch的结构,看到types字段的属性为:DEFAULT NULL。
经过查询资料,在w3schools上找到了答案。
NULL is used as a placeholder for unknown or inapplicable values, it is treated differently from other values.
It is not possible to test for NULL values with comparison operators, such as =, <, or <>. We will have to use the IS NULL and IS NOT NULL operators instead.
也就是说,在SQL中,NULL并不能采用!=与数值进行比较,若要进行比较,我们只能采用IS NULL或IS NOT NULL。
于是,我们将SQL语句改为如下形式:
SELECT * FROM qms_branch WHERE types IS NULL or types != 'dashboard'
再次查询时,结果集就包含performance_trunk分支了。
问题延伸
通过上面例子,我们知道在对NULL进行判断处理时,只能采用IS NULL或IS NOT NULL,而不能采用=, <, <>, !=这些操作符。
那除此之外,还有别的可能存在的坑么?
再看一个例子:
有一张数据表table_foo,其中有一个字段value_field,我们想从这张表中筛选出所有value_field为’value1’,’value2’或NULL的记录。
那么,我们采用IN操作符,通过如下SQL语句进行查询。
SELECT * FROM table_foo WHERE value_field IN ('value1', 'value2', NULL)
这会存在问题么?我们并没有采用=, <, <>, !=对NULL进行比较哦。
答案是同样存在问题!
因为在SQL中,IN语句会被转换为多个=语句。例如,上面例子中的SQL在执行时就会被转换为如下SQL语句:
SELECT * FROM table_foo WHERE value_field = 'value1' OR value_field = 'value2' OR value_field = NULL
而这个时候,执行value_field = NULL时就会出现问题了。
正确的做法应该是将NULL相关的判断独立出来,如下SQL才是正确的写法。
SELECT * FROM table_foo WHERE value_field IN ('value1', 'value2') OR value_field IS NULL
SQL 语句中关于 NULL 的那些坑的更多相关文章
- SQL语句中=null和is null
平时经常会遇到这两种写法:IS NOT NULL与!=NULL.也经常会遇到数据库有符合条件!=NULL的数据,但是返回为空集合.实际上,是由于对二者使用区别理解不透彻. 默认情况下,推荐使用 IS ...
- 关于SQL语句中SUM函数返回NULL的解决办法
SUM 是SQL语句中的标准求和函数,如果没有符合条件的记录,那么SUM函数会返回NULL. 但多数情况下,我们希望如果没有符合条件记录的情况下,我们希望它返回0,而不是NULL,那么我们可以使用例如 ...
- sql 语句中count()有条件的时候为什么要加上or null
参考:https://blog.csdn.net/qq_32719287/article/details/79513164 1.sql 语句中count()有条件的时候为什么要加上or null. 如 ...
- mybatis sql语句中 in() 长度为0或null的情况
mybatis sql语句中 in() 长度为0或null的情况 比如: select * from A where colName IN <foreach collection="m ...
- MyBatis 动态 SQL 语句中出现 '<' 的问题
问题描述 映射接口方法如下: /** * 根据姓名和年龄查询用户信息 * @param name 姓名 * @param user 获取年龄 * @return */ public List<U ...
- SQL语句中count(1)count(*)count(字段)用法的区别
SQL语句中count(1)count(*)count(字段)用法的区别 在SQL语句中count函数是最常用的函数之一,count函数是用来统计表中记录数的一个函数, 一. count(1)和cou ...
- 向已写好的多行插入sql语句中添加字段和值
#region 添加支款方式--向已写好的多行插入sql语句中添加字段和值 public int A_ZhifuFS(int diqu) { ; string strData = @"SEL ...
- SQL点滴35—SQL语句中的exists
原文:SQL点滴35-SQL语句中的exists 比如在Northwind数据库中有一个查询为 SELECT c.CustomerId,CompanyName FROM Customers c WHE ...
- SQL点滴31—SQL语句中@@IDENTITY和@@ROWCOUNT区别
原文:SQL点滴31-SQL语句中@@IDENTITY和@@ROWCOUNT区别 SQL语句中@@IDENTITY和@@ROWCOUNT区别 在一条 INSERT.SELECT INTO 或大容量复制 ...
随机推荐
- docker+k8s基础篇五
Docker+K8s基础篇(五) service资源介绍 A:service资源的工作特性 service的使用 A:service字段介绍 B:ClusterIP的简单使用 C:NodePort的简 ...
- adb常用命令总结
针对移动端 Android 的测试, adb 命令是很重要的一个点,必须将常用的 adb 命令熟记于心, 将会为 Android 测试带来很大的方便,其中很多命令将会用于自动化测试的脚本当中. And ...
- Hbase面试题
hbase的特点 )hbase适合存储海量数据,是一个分布式的,基于列式存储的数据库,基于hadoop的hdfs存储,zookeeper进行管理. )hbase 适合存储半结构化或非结构化的数据,对于 ...
- 嵌入式02 STM32 实验01 端口复用和重映射
内设与外设: 端口复用和端口重映射都需要了解内设和外设,那么什么是内设?什么是外设? 内设:单片机内部集成的功能一般包括:串口模块.SPI模块(Serial Peripheral Interface ...
- ARM中断深入分析几点
ARM中断深入分析几点 1.程序发生中断后,是如何跳转到中断程序里面的? 2.执行完中断后,如何返回到原来被打断的地方接着执行呢? 3.ARM处理器的流水线结构对中断返回地址的计算有什么影响? 4.A ...
- Navicat12下载、激活工具、激活教程
Navicat12的下载地址如下:链接: https://pan.baidu.com/s/11CHIWO74M4-P6UG0aWsF7Q 提取码: bayk 打开激活工具Navicat_Keygen_ ...
- AS3数字取整
AS3 数字取整方法int()去掉小数点trace(int(3.14)); //输出3trace(int(-3.14)); //输出-3Math.round()方法:Math.round()可以四舍五 ...
- Spark 系列(十二)—— Spark SQL JOIN 操作
一. 数据准备 本文主要介绍 Spark SQL 的多表连接,需要预先准备测试数据.分别创建员工和部门的 Datafame,并注册为临时视图,代码如下: val spark = SparkSessio ...
- Hadoop2-认识Hadoop大数据处理架构-单机部署
一.Hadoop原理介绍 1.请参考原理篇:Hadoop1-认识Hadoop大数据处理架构 二.centos7单机部署hadoop 前期准备 1.创建用户 [root@web3 ~]# useradd ...
- wpf Log4net的配置和使用
现在项目涉及的是cs客户端,在项目中使用log4net记录本地日志和异常信息,这里项目做完了,想着自己做一个demo,测试记录一下log4Net的配置使用. 第一步.新建一个wpf应用程序,项目右键 ...