必须用(col1 = col2) OR (col1 IS NULL AND col2 IS NULL)判断两列是否相等,因NULL = anything恒返回NULL而非TRUE/FALSE;IS NOT DISTINCT FROM在MySQL中不推荐生产使用。

直接用 = 比较两列会遇到 NULL 问题
很多人写 SELECT col1 = col2 AS is_same FROM table,在 MySQL 里看似能跑,但只要其中一列是 NULL,结果就变成 NULL 而不是 FALSE。SQL 中 NULL = anything 永远返回 NULL,不是布尔值。这不是 bug,是三值逻辑的设定。
正确做法是显式处理 NULL:
- 用
IS NOT DISTINCT FROM(PostgreSQL、SQL:2003 标准支持,但 MySQL 和 SQL Server 不原生支持) - 用
(col1 = col2) OR (col1 IS NULL AND col2 IS NULL)—— 兼容性最好,所有主流数据库都行 - 避免用
COALESCE(col1, '') = COALESCE(col2, ''),它可能掩盖语义差异(比如0和''强转后相等)
MySQL 用户必须绕开 IS NOT DISTINCT FROM
MySQL 直到 8.0.22 才实验性支持 IS NOT DISTINCT FROM,且默认禁用。生产环境别依赖。稳妥写法是:
SELECT col1, col2, (col1 = col2) OR (col1 IS NULL AND col2 IS NULL) AS is_same FROM my_table;
注意:如果列类型不同(比如 VARCHAR 和 INT),MySQL 会隐式转换,可能导致意外结果。建议提前确认类型一致,或显式 CAST。
SQL Server 中用 IIF 或 CASE 更清晰
SQL Server 不支持 IS NOT DISTINCT FROM,但 IIF 写起来更紧凑:
SELECT col1, col2, IIF((col1 = col2) OR (col1 IS NULL AND col2 IS NULL), 1, 0) AS is_same FROM my_table;
或者用标准 CASE(兼容性更好):
SELECT col1, col2, CASE WHEN (col1 = col2) OR (col1 IS NULL AND col2 IS NULL) THEN 1 ELSE 0 END AS is_same FROM my_table;
别用 CONVERT(BOOLEAN, ...) —— SQL Server 根本没有原生 BOOLEAN 类型,会报错。
WHERE 条件里复用这个逻辑要小心性能
如果想筛选“两列相等”的记录,直接写 WHERE (col1 = col2) OR (col1 IS NULL AND col2 IS NULL) 是安全的,但无法走索引(除非你建函数索引或计算列)。常见优化方式:
- 加一个持久化计算列:
ALTER TABLE t ADD is_col1_col2_same AS (CASE WHEN (col1 = col2) OR (col1 IS NULL AND col2 IS NULL) THEN 1 ELSE 0 END) PERSISTED; - 然后在这个列上建索引:
CREATE INDEX IX_t_is_same ON t(is_col1_col2_same);
否则每次查询都要全表扫描做空值判断,大数据量时延迟明显。

















