sql中下划线_在like中是单字符通配符,需用escape显式转义(如escape '!')才能匹配字面量_;insert时无需转义,仅查询时like才需处理;跨库推荐统一用escape子句并选安全转义符如!。

SQL中下划线_被当作通配符,不是字面量
在 LIKE 查询里,_ 代表“任意单个字符”,所以直接写 WHERE name LIKE 'a_b' 会匹配 aab、acb,而不是字面意义的 a_b。这不是“转义没做好”,而是 SQL 标准行为。
解决办法是显式指定一个转义字符,再用它修饰 _:
- 用
ESCAPE子句声明转义符,例如ESCAPE '' - 之后所有跟在转义符后的
_或%都按字面量处理 - 注意:转义符本身若需出现,要写两次,比如想搜字符串
backslash,且用作转义符,则写成'back\slash'
示例:SELECT * FROM users WHERE username LIKE 'admin_test' ESCAPE ''; —— 这才真正匹配用户名为 admin_test 的记录。
不同数据库对转义符的支持和默认行为不一致
MySQL 默认允许反斜杠 作为转义符(但需开启 NO_BACKSLASH_ESCAPES SQL mode 才禁用),PostgreSQL 默认不认 ,必须显式写 ESCAPE;SQL Server 用方括号 [_] 或 ESCAPE 都行,但后者更通用。
跨库兼容写法建议:
- 统一用
ESCAPE显式声明,别依赖默认转义符 - 选一个安全的转义符:如
!或~,它们本身很少出现在业务数据里 - 避免用
,尤其在拼接动态 SQL 时容易和编程语言字符串转义冲突
例子:WHERE path LIKE 'config!_settings' ESCAPE '!' 在 PostgreSQL / MySQL / SQLite 中都可靠。
INSERT 时下划线不需要特殊处理,除非字段值参与 LIKE 查询
很多人混淆了“存数据”和“查数据”。往表里 INSERT INTO logs(msg) VALUES ('error_code_404'); 完全不需要转义——_ 就是普通字符,数据库原样存。
只有当你后续用 LIKE 去匹配这个字段时,才需要考虑转义逻辑:
- 如果查的是精确值,用
=,不是LIKE,就完全不用管 - 如果必须用
LIKE(比如前缀搜索'error%'),而模式里又含_,才需要ESCAPE - ORM 如 SQLAlchemy、MyBatis 等通常提供
escape参数或专用方法(如like(..., escape='!'))
用参数化查询时,转义逻辑仍在 SQL 层,不是应用层
参数化查询(如 WHERE name LIKE ?)只防止 SQL 注入,不自动处理 LIKE 通配符语义。传入的参数值如果含 _,仍会被当通配符解释。
正确做法是:把转义逻辑写进 SQL 模板,参数只负责值本身:
- ❌ 错误:
WHERE name LIKE ? ESCAPE ''+ 绑定参数'admin_test'(应用层加了,但 SQL 层未声明转义符) - ✅ 正确:
WHERE name LIKE ? ESCAPE '!'+ 绑定参数'admin!_test'(转义符和逻辑都在 SQL 层定义) - 或者更稳妥:
WHERE name = ?,避开LIKE就彻底没这问题
真正容易被忽略的是:哪怕用了 ORM,只要生成的 SQL 含 LIKE 和字面 _,就必须同步处理 ESCAPE 子句——它不在参数里,也不在驱动自动补全范围内。










