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

时间: 2024-07-31 14:31:18

SQL 语句中关于 NULL 的那些坑的相关文章

SQL语句中=null和is null

平时经常会遇到这两种写法:IS NOT NULL与!=NULL.也经常会遇到数据库有符合条件!=NULL的数据,但是返回为空集合.实际上,是由于对二者使用区别理解不透彻. 默认情况下,推荐使用 IS NOT NULL去做条件判断,因为SQL默认情况下对WHERE XX!= Null的判断会永远返回0行,却不会提示语法错误. 这是为什么呢? SQL Server文档中对Null值的比较运算定义了两种规则,如在SQL Server 2000中: 规则一是是ANSISQL(SQL-92)规定的Null

关于SQL语句中SUM函数返回NULL的解决办法

SUM 是SQL语句中的标准求和函数,如果没有符合条件的记录,那么SUM函数会返回NULL. 但多数情况下,我们希望如果没有符合条件记录的情况下,我们希望它返回0,而不是NULL,那么我们可以使用例如下面的方法来处理: SELECT COALESCE(SUM(name),0) FROM person WHERE id > 0   行了,这下就不用费事去处理返回结果是否为NULL的情况了. COALESCE 函数的意思是返回参数列表中第一个为空的值,该方法允许传入多个参数,该函数也是SQL中的标准

sql 语句中count()有条件的时候为什么要加上or null

参考:https://blog.csdn.net/qq_32719287/article/details/79513164 1.sql 语句中count()有条件的时候为什么要加上or null. 如count(province = '浙江' or NULL) 这部分,为什么要加上or NULL,直接count(province='浙江')有什么问题吗?不就是要找province = '浙江'的数据吗,为什么要计算NULL的数据. 答案:因为当 province不是浙江时 province='浙

mybatis sql语句中 like in() 长度为0或null的情况

mybatis sql语句中 like in() 长度为0或null的情况 比如: select * from A where colName LIKE IN <foreach collection="moCodeList" item="item" index="index" open="(" close=")" separator=","> #{item} </for

SQL SERVER 中is null 和 is not null 将会导致索引失效吗?

原文:SQL SERVER 中is null 和 is not null 将会导致索引失效吗? 其实本来这个问题没有什么好说的,今天优化的时候遇到一个SQL语句,因为比较有意思,所以我截取.简化了SQL语句,演示给大家看,如下所示 declare @bamboo_Code varchar(3);   set @bamboo_Code='-01';     SELECT DISTINCT yarn_lot FROM   dbo.rsjob WITH ( nolock ) WHERE  RIGHT(

SQL语句中count(1)count(*)count(字段)用法的区别

SQL语句中count(1)count(*)count(字段)用法的区别 在SQL语句中count函数是最常用的函数之一,count函数是用来统计表中记录数的一个函数, 一. count(1)和count(*)的区别 1. count(1)和count(*)的作用: 都是检索表中所有记录行的数目,不论其是否包含null值. 2. 区别:但是count(1)比count(*)效率更高 二 . count(字段)与count(1)和count(*)的区别 count(字段)的作用是检索表中的这个字段

SQL语句中 NOT IN 子句的“正确打开方式”

在写SQL语句的时候,若where条件是判断用户不在某个集合当中,我们习惯使用 where 列名 not in (集合) 子句,然而,当集合中存在空值时,返回的结果永远为空.如下所示: Oracle 或 MySQL select 1 from dual where 1 not in(2, null) 返回0条结果. SQL Server select 1 where 1 not in(2, null) 返回0条结果. 显然在上面例子中的结果并非我们希望得到的结果.对于数据库管理系统 select

SQL点滴31—SQL语句中@@IDENTITY和@@ROWCOUNT区别

原文:SQL点滴31-SQL语句中@@IDENTITY和@@ROWCOUNT区别 SQL语句中@@IDENTITY和@@ROWCOUNT区别 在一条 INSERT.SELECT INTO 或大容量复制语句完成后,@@IDENTITY 中包含语句生成的最后一个标识值. 如果语句未影响任何包含标识列的表,则 @@IDENTITY 返回 NULL. 如果插入了多个行,生成了多个标识值,则 @@IDENTITY 将返回最后生成的标识值. 如果语句触发了一个或多个触发器,该触发器又执行了生成标识值的插入操

SQL点滴35—SQL语句中的exists

原文:SQL点滴35-SQL语句中的exists 比如在Northwind数据库中有一个查询为 SELECT c.CustomerId,CompanyName FROM Customers c WHERE EXISTS( SELECT OrderID FROM Orders o WHERE o.CustomerID=c.CustomerID) 这里面的EXISTS是如何运作呢?子查询返回的是OrderId字段,可是外面的查询要找的是CustomerID和CompanyName字段,这两个字段肯定