这触及了 MySQL 中一个非常重要且容易被忽略的细节:字符转义。
1. 是的,`~` 在 MySQL 中确实有特殊意义,但通常不是在普通字符串上下文中,而是在正则表达式中。在正则表达式中,`~` 表示“按位取反”或“匹配不在列表中的字符”,但更常见的是与其它字符组合使用(如 `~*` 在 PostgreSQL 中表示不区分大小写匹配,但 MySQL 不支持此用法)。然而,导致你问题的原因通常不是它的正则表达式含义。
2. 查询 `~` 却返回不包含它的结果,根本原因是你没有对 `~` 进行转义,导致它后面的字符被当作普通字符处理,查询实际上变成了模糊匹配那些字符。
■ 详细解释和问题根源
你的 SQL 语句很可能长这样:
SELECT * FROM your_table WHERE your_column LIKE '%~%';
你期望的是查找所有包含 `~` 字符的记录。但结果却返回了包含 `~` 后面那个字符的记录。
核心原因在于:`~` 是 MySQL 中的默认转义字符。
在 MySQL 的 `LIKE` 语句中,百分号 `%` 和下划线 `_` 是特殊字符(通配符)。如果你想搜索它们本身,就需要用转义字符来告诉 MySQL:“请把我后面这个百分号当作一个普通的百分号字符,而不是通配符”。
默认的转义字符就是反斜杠 `\`。但 MySQL 允许你使用 `ESCAPE` 关键字来自定义转义字符。而 `~` 正是一个常见的用于自定义的转义字符。
当你在语句中没有使用 `ESCAPE` 子句时,MySQL 的行为是不确定的,它可能会将某些字符(如 `~`)解释为转义字符的开端。在你的情况下,MySQL 将 `~%` 中的 `~` 解释为转义字符,而 `%` 被转义后,就失去了通配符的含义,变成了一个普通的百分号 `%` 字符。
所以,你的查询:
... WHERE your_column LIKE '%~%'
被 MySQL 理解为了:
> “查找所有在任意位置包含一个字面百分号 `%` 的记录”
这就是为什么你看到了不包含 `~`,但包含 `%` 的结果。
■ 正确的解决方法
你有几种方法来正确搜索 `~` 字符:
▲ 方法一:使用默认的转义字符(反斜杠 `\`)
这是最标准和推荐的方法。
SELECT * FROM your_table WHERE your_column LIKE '%\~%';
通过 `\~`,你明确地告诉 MySQL:这是一个普通的波浪号字符。
▲ 方法二:明确指定使用 `~` 作为转义字符并转义自身
这种方法有点绕,但可以帮你理解原理。
SELECT * FROM your_table WHERE your_column LIKE '%~~%' ESCAPE '~';
这里 `ESCAPE '~'` 声明使用 `~` 作为转义字符。`~~` 中的第一个 `~` 是转义字符,它告诉 MySQL:“我后面这个 `~` 是普通字符,不是通配符”。
▲ 方法三:使用函数代替 LIKE(如果模式简单)
如果只是简单地查找是否包含某个字符,使用 `INSTR()` 或 `LOCATE()` 函数可以完全避免转义问题。
SELECT * FROM your_table WHERE INSTR(your_column, '~') > 0;
或者
SELECT * FROM your_table WHERE LOCATE('~', your_column) > 0;
■ 总结与最佳实践
| 场景 | 正确写法 | 说明 |
| :--- | :--- | :--- |
| 搜索包含 `~` | `LIKE '%\~%'` | 使用默认反斜杠转义 |
| 搜索包含 `%` | `LIKE '%\%%'` | 转义百分号 |
| 搜索包含 `_` | `LI LIKE '%\_%'` | 转义下划线 |
| 搜索包含 `\` | `LIKE '%\\%'` | 转义反斜杠本身需要两个反斜杠 |
| 避免转义 | `WHERE INSTR(col, '~') > 0` | 使用函数代替 `LIKE` |
结论:
你遇到的问题是由于 `~` 在未经转义的情况下,在某些 MySQL 环境或上下文中被解释为了转义字符,导致其后面的通配符 `%` 被转义成了普通字符。永远记得对 SQL 查询中的特殊字符进行转义是一个非常重要的安全性和准确性的实践。对于 `LIKE` 操作,坚持使用 `\` 作为转义字符是最佳选择。