SQL 中 NULL 与空字符串 ‘’ 的比较行为差异汇总

9次阅读

NULL与”在sql中行为截然不同:WHERE col = NULL恒不成立,须用IS NULL;空字符串用= ”匹配;聚合函数对二者处理差异大,需用NULLif或COALESCE统一处理。

SQL 中 NULL 与空字符串 ‘’ 的比较行为差异汇总

NULL 与 ” 在 WHERE 条件中的行为完全不同

直接写 WHERE col = '' 能命中空字符串,但 WHERE col = NULL 永远不返回任何行——因为 SQL 中任何与 NULL 的等值比较(=!=)结果都是 UNKNOWN,而 WHERE 只接受 TRUE

NULL 必须用 IS NULL,查非空字符串且排除 NULL 得写成:col != '' AND col IS NOT NULL

  • col = '':只匹配存储值为零长度字符串的行
  • col IS NULL:只匹配该列未赋值或显式设为 NULL 的行
  • col = NULLcol != NULL:语法合法,但逻辑恒为假,无实际筛选效果
  • 某些 ORM(如 Django)自动生成的查询可能混淆二者,需检查生成 SQL

聚合函数对 NULL 和 ” 的处理差异

count(col) 忽略 NULL,但会计入 ''SUM()AVG()MAX()MIN() 全部跳过 NULL,却把 '' 当作有效值参与计算——这在字符类型上通常报错(如 SUM('')postgresqlinvalid input syntax for type numeric),但在 mysql 的宽松模式下可能隐式转为 0,造成静默偏差。

  • COUNT(*) 统计所有行,COUNT(col) 只统计 col IS NOT NULL 的行
  • COALESCE(col, 'N/A') 可统一兜底,但注意:若 col'',不会触发替换
  • NULLIF(col, '') 可把空字符串转为 NULL,再配合聚合更安全

ORDER BY 中 NULL 和 ” 的排序位置受方言控制

标准 SQL 规定 NULLS FIRST / NULLS LAST,但 MySQL 默认把 NULL 排最前,PostgreSQL 默认排最后;而 '' 始终按字典序参与排序,和普通字符串一样。这意味着 ORDER BY name 的结果在不同数据库里,NULL 行的位置可能上下翻转,但 '' 行总在 'a' 前、' ' 后(因 ASCII 值为 0)。

  • MySQL 8.0+ 支持显式 NULLS LAST,但旧版只能靠 ORDER BY IF(col IS NULL, 1, 0), col 模拟
  • ''' '(空格)不是一回事:Length(' ') 是 1,LENGTH('') 是 0
  • 前端分页时若依赖排序稳定性,必须明确处理 NULL 位置,否则同一页数据可能重复或丢失

INSERT 和 default 对 NULL 与 ” 的隐式转换风险

定义列为 TEXT DEFAULT '' 时,显式插入 NULL 会存成 NULL(除非加 NOT NULL 约束);但若列定义为 TEXT DEFAULT NULL,又没指定值,才真正存 NULL。更大的陷阱是某些客户端或 ORM 在字段为空时自动发 '' 而非 NULL,导致业务上“未填写”被记为“填了空值”。

  • 建表时优先用 NOT NULL DEFAULT '' 明确语义,避免歧义
  • MySQL 的 STRICT_TRANS_TABLES 模式下,向 NOT NULL 列插入 '' 是允许的;但插入 NULL 会报错
  • csv 导入时,缺失字段常被解析为 NULL,而空字段(,,)可能是 '',需预处理统一

真正麻烦的不是记不住规则,而是同一个字段在应用层、ORM 层、DB 层、迁移脚本里可能被不同方式初始化或校验——NULL'' 看似微小,一旦混用,查数、统计、导出全会偏移。

text=ZqhQzanResources