因为\_在like中默认是通配符而非字面下划线,必须用escape显式声明转义符(如escape '!')才能匹配真实下划线,否则'user\_%'会误匹配usera、user1等任意单字符组合。

WHERE name LIKE 'user_%' 为什么查不到 user_ 开头的记录
因为 _ 在 LIKE 中是通配符,代表“任意单个字符”,不是下划线字面量。写 name LIKE 'user_%' 实际会匹配 userA、user1、user (空格),而不是 user_abc 这类真实含下划线的值。
必须显式声明转义符,不能靠反斜杠自动生效——MySQL 在 NO_BACKSLASH_ESCAPES 模式下会直接忽略 \_,PostgreSQL 默认不解释反斜杠,SQL Server 更倾向用方括号语法。
- 正确写法:
WHERE name LIKE 'user!_%' ESCAPE '!' -
ESCAPE后只能跟一个 ASCII 可打印字符,推荐!、$或|,避开字母、数字和常见业务符号 - 转义只作用于紧跟在转义符后的那个字符:在
'A!_B%'中,只有_被转义,末尾的%仍是通配符
用户输入 "50%" 怎么安全传进 LIKE 查询
参数化查询(如 PreparedStatement)能防 SQL 注入,但不会改 LIKE 的语义。传入原始字符串 "50%",WHERE price LIKE ? 仍会把 % 当通配符用,结果不是查“含 50% 的字段”,而是“以 50 开头的任意字符串”。
必须在应用层完成转义,再把转义后字符串作为参数传入:
- 用户输入:
"disk % drive" - 应用层替换:
"disk !% drive"(用!作转义符) - SQL 写成:
WHERE desc LIKE ? ESCAPE '!',参数值为"disk !% drive" - 如果用户输入里已含转义符(如搜
"cost!%"),得先对!二次转义:"cost!!%",否则数据库会误判为转义动作
不同数据库对 [ ] 和 ^ 的处理差异极大
[、]、^ 是 SQL Server 等方言中扩展的通配符,但在标准 LIKE 里不属于通用语法。比如想查字段值含 "Field[abc]Value" 的记录,直接写 LIKE '%Field[abc]Value%' 会被当成“匹配 Field + 任意一个 a/b/c 字符 + Value”,而非字面字符串。
跨库项目务必避开方括号语法,统一用 ESCAPE:
- 错误(仅 SQL Server 可用):
WHERE name LIKE '%Field[[]abc[]]Value%' - 正确(通用):
WHERE name LIKE '%Field/[abc/]Value%' ESCAPE '/' - 注意:左方括号
[本身也要被转义,所以/[才表示字面[ - PostgreSQL 对
!作转义符时,若字段值真含!,该行永远无法命中——这不是 bug,是规范行为
LIKE '%xxx%' 为什么慢,转义后更慢?
LIKE 左侧带 %(如 '%xxx%')基本无法利用 B-Tree 索引,数据库只能全表扫描。加了 ESCAPE 不会改善性能,反而可能因模式复杂度增加解析开销。
真正影响响应时间的,往往不是转义写法本身,而是没意识到模糊位置带来的索引失效:
-
LIKE 'prefix%'→ 可走索引(前缀匹配) -
LIKE '%suffix'或LIKE '%mid%'→ 几乎必全表扫描 - 转义后的
LIKE '%50!%%' ESCAPE '!',开头仍是%,索引照样失效 - 大数据量场景下,优先考虑全文索引(如 MySQL
MATCH AGAINST、PostgreSQLtsvector),而非硬扛LIKE
最容易被忽略的点是:转义符选哪个不关键,关键是整个链路——用户输入、应用层替换、SQL 拼接、数据库执行——每一步都用同一个转义符,且确认该字符在真实数据中确实不存在。漏掉任一环,LIKE 就既不安全也不准确。










