我在做一个需求是这样的:联查多张表,并且更据条件返回数据。
但是,根据我的WHERE条件获取到的数据总是不正确,通过反复的研究,发现了问题的所在:
某些列的值为NULL,在把这些列作为条件时,就会匹配不到正确的值,故而返回不正确的数据。
示例:
数据表(Users)及数据如下:
需求:查询所有数据中,Name不是以’L’开头并且Mobile中不包含’186’ 的数据
SQL语句:
查询结果如下:
奇怪,为什么获取不到数据呢?实际应该返回ID等于4和5的数据才对的。
于是,我思考了起来。。。。。。。。。思考中。。。。。。。。。
突然,眼前一亮,请注意:数据列中为NULL的地方 , 是的,没错问题就处在这里。
那么什么是NULL值呢???
NULL表示值为空,为空就是说该字段还没有经行任何的赋值操作,它的值是未知的,所以我们无法拿它与其他类型的值经行比较,如果用它去和其他值比较的话,那么返回的一定是未知,这样,我们得到的数据就是不准确的数据了。
说道NULL值,就一定得说一下什么是三值逻辑,在SQL中有逻辑运算和比较运算,他们的取值一般有两种:True和False ,但是在表达式中涉及到NULL值的时候,取值就会是第三种,即UNKNOWN
关于UNKNOWN的相关知识点整理如下:
1、NOT TRUE 等于 FALSE,,NOT FALSE 等于 TRUE,,否定的UNKNOWN还是UNKNOWN;
2、比较两个NULL值,将返回FALSE而不是UNKOWN;
3、所有的查询筛选器(ON、WHERE和HAVING)都会把UNKNOWN当作FALSE处理,UNKNOWN的行会被排除在结果集之外;
4、CHECK约束中的UNKNOWN被当作TRUE来处理,假设表中包含一个CHECK约束,要求salary列的值必须大于0,向该表插入salary为NULL的行时可以被接受;
5、如果表中有一列定义了UNIQUE约束,将无法向表中插入两行该列值为NULL的数据;
6、GROUP BY会把所有NULL值分组到一起;ORDER BY 会把所有的NULL值排列在一起;
7、NULL值在聚合函数里的使用有点意思:Count(*)会返回表中的所有行,Count(salary)将会排除掉salary为NULL的行;
使用AVG(salary)求平均值时也会排除掉salary为NULL的行,这样可能会导致计算的平均值不准确,需要将NULL转换成0或其它默认值再参与计算;
在数据库设计时,关键字段上应考虑设计默认值,防止在统计时出现误差;
(摘自:http://www.cnblogs.com/Yuanet/archive/2011/03/17/1986808.html ,我是看了这些才学习到三值逻辑的 :) )
好了,先说到这儿,继续处理需求,怎么避免NULL值呢???
很简单,既然NULL值无法和其他值进行比较,那么,我们就先对它进行转换,让它和要比较的值类型一致,这样就可以了。这里,我们使用ISNULL函数来完成转换。
先说一下ISNULL函数的语法
ISNULL ( check_expression , replacement_value )
check_expression:将被检查是否为 NULL 的表达式。 check_expression 可以为任何类型。
replacement_value:当 check_expression 为 NULL 时要返回的表达式。 replacement_value 必须是可以隐式转换为 check_expresssion 类型的类型。
ISNULL函数的返回类型:如果文字 NULL 作为 check_expression 提供,则返回 replacement_value 的数据类型。 如果文字 NULL 作为 check_expression 提供并且未提供 replacement_value,则返回 int。
(具体ISNULL的相关信息,参见MSDN:http://msdn.microsoft.com/zh-cn/library/ms184325.aspx)
好了,来看看用ISNULL处理过的T-SQL语句吧:
SELECT * FROM dbo.Users WHERE ISNULL([Name],'') NOT LIKE 'L%' AND ISNULL(Mobile,'') NOT LIKE '%186%'
执行结果如下:
OK,这回,得到了我们想要的结果,问题解决了。