请教SQL中CASE与WHERE语句里ISNULL的作用及省略影响
先说说为啥要用到ISNULL:
ISNULL的核心作用就是把NULL值替换成你指定的默认值,在你的示例里是换成空字符串''。这么做全是因为SQL里NULL的特殊脾气——任何和NULL的比较结果都是UNKNOWN,既不是真也不是假,直接用的话会让条件判断彻底失效。
你的UpdateTime是时间类型,要是它为NULL,直接和其他时间或者变量比根本出不来正常结果。用ISNULL把NULL转成空字符串后,SQL Server会自动把空字符串转成1900-01-01这个最早的时间,这样就能正常做大小比较了。
对应你给的两个示例:
示例1(CASE语句)
要是不用ISNULL,只要DB1.UpdateTime或者DB2.UpdateTime有一个是NULL,那NULL >= 某个时间或者NULL >= NULL的结果都是UNKNOWN,CASE会直接跳到ELSE分支。比如DB1.UpdateTime有值、DB2.UpdateTime是NULL的时候,本来应该取DB1.UpdateTime,结果因为比较出了UNKNOWN,CASE会返回DB2.UpdateTime也就是NULL,这完全不符合“取更新时间较晚的那个”的逻辑。用了ISNULL之后,NULL被当成最早的时间来比,就能保证比较逻辑正常跑,拿到正确的最大更新时间。
示例2(WHERE过滤)
要是不用ISNULL,当DB1.UpdateTime是NULL时,NULL >= @StartTime的结果是UNKNOWN,SQL会把UNKNOWN当成FALSE处理,这条数据就被过滤掉了。用ISNULL把NULL转成1900-01-01后,因为你的@StartTime是2022-01-01,1900年的时间肯定比2022年早,所以这条数据还是会被过滤——看起来结果一样?但要是你的@StartTime是比1900更早的时间(虽然这种情况很少见),或者你把ISNULL的替换值改成了当前时间,结果就完全不一样了。说白了,用ISNULL就是给NULL值一个明确的比较基准,避免因为NULL的特殊特性搞出意外的过滤结果。
再说说省略ISNULL会有啥影响:
对示例1的影响
- 当
DB1.UpdateTime是NULL、DB2.UpdateTime有值:NULL >= DB2.UpdateTime结果是UNKNOWN,CASE走ELSE返回DB2.UpdateTime,这其实是对的;但如果DB2.UpdateTime也是NULL,CASE会返回NULL,而用ISNULL的话会返回1900-01-01(空字符串转的)。 - 当
DB1.UpdateTime有值、DB2.UpdateTime是NULL:DB1.UpdateTime >= NULL结果是UNKNOWN,CASE走ELSE返回NULL,但用ISNULL的话会返回DB1.UpdateTime,这就和你想要的“取较晚时间”的逻辑完全相反了。
对示例2的影响
当DB1.UpdateTime是NULL时,省略ISNULL会直接把这条数据过滤掉。如果你的业务逻辑是“从未更新的老数据(UpdateTime为NULL)也要保留”,那这就会错误过滤掉这些数据;就算业务逻辑是要过滤NULL,这么写也不够严谨——你是依赖了SQL对UNKNOWN的默认处理逻辑,而不是明确指定了NULL的处理方式,后续维护的时候很容易出问题。
最后提一句:不同数据库的NULL替换函数不一样,你用的ISNULL是SQL Server的,MySQL用IFNULL,PostgreSQL用COALESCE,但核心都是替换NULL,避免比较时出问题。
内容的提问来源于stack exchange,提问作者Antoine

