not like 不能真正“反向模糊匹配”,它仅排除符合like模式的行,不处理null和空字符串;正确写法需显式添加name is not null and name != ''等条件。

NOT LIKE 能否真正“反向模糊匹配”?
不能。这是最常见的误解:NOT LIKE 并不是“匹配不满足模糊条件的字符串”,而是“排除明确符合 LIKE 模式的行”。它不等价于“所有其他可能字符串”,尤其在含 NULL 或空字符串时行为易被忽略。
例如:WHERE name NOT LIKE '%a%' 会漏掉 name IS NULL 的记录(因为 NULL 与任何布尔表达式比较都为 UNKNOWN),也不会匹配空字符串 ''(若该值实际存在且非 NULL)。
正确写法:必须显式处理 NULL 和边界情况
要真正覆盖“不含字母 a 的非空有效值”,得把逻辑补全:
WHERE name NOT LIKE '%a%' AND name IS NOT NULL AND name != ''- 若字段允许空格填充(如
CHAR(10)),还要加TRIM(name) != '' - 区分大小写敏感性:MySQL 默认不区分,PostgreSQL / SQL Server 默认区分;必要时用
ILIKE(PostgreSQL)或LOWER(name) NOT LIKE '%a%'
性能陷阱:NOT LIKE 几乎无法走索引
即使你写了 name NOT LIKE 'A%',数据库也几乎不会使用 name 上的 B-Tree 索引——因为 NOT LIKE 本质是“排除一个范围”,优化器更倾向全表扫描。
替代思路(视场景而定):
- 改用正则(如 PostgreSQL 的
NOT name ~ 'a'),但同样难索引 - 提前物化特征:新增布尔列
has_a BOOLEAN,用触发器或应用层维护,然后查WHERE NOT has_a - 若模式固定(如“不含前缀 X_”),可考虑
WHERE name !~ '^X_'+ 函数索引(PostgreSQL)
常见错误现象和调试建议
执行后结果比预期少?大概率是 NULL 搞的鬼。快速验证:
- 先查
SELECT COUNT(*) FROM t WHERE name IS NULL - 再查
SELECT COUNT(*) FROM t WHERE name NOT LIKE '%x%' OR name IS NULL—— 对比数量差 - 用
COALESCE(name, '') NOT LIKE '%x%'强制转空串(注意:这会改变语义,仅用于调试)
最稳妥的做法,永远把 IS NOT NULL 和业务上有效的非空判断(比如 TRIM(name) '')写进 WHERE 条件里,别指望 NOT LIKE 自动兜底。










