NOT LIKE 是 LIKE 的逻辑否定,必须配合通配符(如 %、_)使用;单独写 NOT LIKE 'str' 等价于 != 'str' 但语义模糊,应避免;它不匹配 NULL(返回 UNKNOWN 而被 WHERE 过滤),需显式处理;多数形式无法走索引,性能差。

NOT LIKE 语法结构和基础用法
直接写 NOT LIKE 就行,它不是独立函数,而是 LIKE 的逻辑否定,必须配合通配符使用。不加通配符(比如写成 WHERE name NOT LIKE 'John')等价于 != 'John',但语义模糊、易误解,应避免。
常见错误是漏掉通配符却以为在做“模糊排除”,结果查出大量意外数据。正确写法必须明确意图:想排除以某前缀开头?用 NOT LIKE 'prefix%';排除含某子串?用 NOT LIKE '%substring%';排除以某后缀结尾?用 NOT LIKE '%suffix'。
-
NOT LIKE 'A%'排除所有以 A 开头的记录 -
NOT LIKE '%test%'排除所有字段中包含 test 的记录 -
NOT LIKE '%_tmp'(下划线是单字符通配符)排除以任意单字符 + tmp 结尾的记录
NULL 值会让 NOT LIKE 返回 UNKNOWN 而非 TRUE
这是最容易被忽略的坑:当字段为 NULL 时,column NOT LIKE '%abc%' 的结果既不是 TRUE 也不是 FALSE,而是 UNKNOWN,而 SQL 的 WHERE 子句只保留计算结果为 TRUE 的行 —— 所以 NULL 记录默认被过滤掉,哪怕你本意是保留它们。
如果业务上需要保留 NULL,必须显式处理:
- 用
OR column IS NULL补充条件:WHERE column NOT LIKE '%bad%' OR column IS NULL - 用
COALESCE转换空值:WHERE COALESCE(column, '') NOT LIKE '%bad%'(注意:空字符串参与匹配可能改变语义) - 某些数据库(如 PostgreSQL)支持
IS NOT DISTINCT FROM,但兼容性差,不推荐通用场景
不同数据库对大小写和转义字符的处理差异
NOT LIKE 的行为高度依赖数据库的 collation 和配置。例如:
- MySQL 默认
utf8mb4_general_ci是大小写不敏感的,NOT LIKE 'abc%'会同时排除ABC123和abc456 - PostgreSQL 默认大小写敏感,
NOT LIKE 'abc%'不排除ABC123,要写成NOT ILIKE 'abc%'(ILIKE是 PostgreSQL 特有大小写不敏感变体) - SQL Server 支持
ESCAPE子句定义转义符,如NOT LIKE '%50!% off%' ESCAPE '!'可匹配字面量50% off;而 SQLite 不支持ESCAPE,得用REPLACE预处理或改用正则(如果启用)
跨库迁移时,仅靠 NOT LIKE 很难保证行为一致,建议把模式逻辑抽到应用层或用标准化函数封装。
性能隐患:NOT LIKE 几乎无法使用索引
除了 NOT LIKE 'prefix%' 这种前缀型(且数据库支持前缀索引优化)外,其余形式如 NOT LIKE '%suffix' 或 NOT LIKE '%middle%' 都会导致全表扫描。原因很简单:B-tree 索引无法高效反向定位“不匹配某模式”的记录。
如果表很大且查询频繁,考虑以下替代方案:
- 把要排除的模式建为单独的黑名单表,用
LEFT JOIN ... WHERE blacklist.id IS NULL替代NOT LIKE - 增加计算列(如
is_bad_pattern AS (CASE WHEN name LIKE '%spam%' THEN 1 ELSE 0 END)),对该列建索引并查WHERE is_bad_pattern = 0 - 用全文检索(如 PostgreSQL 的
to_tsvector或 MySQL 的FULLTEXT)替代模糊匹配,再取补集
真正麻烦的不是写法,而是误以为 NOT LIKE 能走索引 —— 实际执行计划里一看到 Seq Scan 或 Table Scan 就该警觉。

















