SQL的WHERE IN子句中是否可以包含NULL值?
错误写法原因
你遇到的问题是SQL中NULL比较的通用规则导致的:SQL里所有和NULL的等值比较(包括=、IN子句的隐式等值匹配)结果都是UNKNOWN,WHERE条件仅会保留判断结果为TRUE的行。
你写的WHERE s.plan_type IN (NULL, 'basic')等价于:
WHERE s.plan_type = NULL OR s.plan_type = 'basic'
其中s.plan_type = NULL永远返回UNKNOWN,因此这条语句只会筛选出持有基础套餐的用户,完全漏掉了无套餐的NULL记录,所以不符合预期。
简洁写法参考
你当前使用的WHERE s.plan_type IS NULL OR s.plan_type = 'basic'是SQL标准兼容、可读性最高的写法,所有主流数据库都支持,日常场景优先推荐使用。
如果需要更短的写法,可以用SQL标准函数COALESCE实现:
WHERE COALESCE(s.plan_type, 'basic') = 'basic'
COALESCE函数会返回第一个非NULL的参数,这里会把NULL的plan_type替换为'basic'再做等值判断,和你原来的OR写法逻辑完全一致,性能也没有明显差异,MySQL、PostgreSQL、SQL Server、Oracle等主流数据库均支持该函数。
部分数据库还有专属简化函数,比如MySQL的IFNULL、SQL Server的ISNULL,用法和COALESCE类似,但兼容性不如COALESCE,不优先推荐。
NULL判断的通用规则
SQL标准中,判断一个值是否为NULL 必须使用IS NULL/IS NOT NULL语法,所有= NULL、IN (NULL)、!= NULL这类写法都不会得到预期结果,没有例外。
内容的提问来源于stack exchange,提问作者Nicholas Hassan

