SQL中单引号导致语法错误的直接原因是解析器将第一个'视为字符串起始,遇到O'Reilly中的第二个'即认为字符串提前终止,致使后续Reilly');成为非法语法;必须用两个连续单引号''转义,且参数化查询才是唯一安全方案。

SQL里单引号导致语法错误的直接原因
执行 INSERT INTO users (name) VALUES ('O'Reilly'); 时,数据库把第一个 ' 当作字符串开头,遇到 O' 中的第二个 ' 就认为字符串提前结束,后面 Reilly'); 变成非法语法。这不是数据问题,是 SQL 解析器在读取语句阶段就报错,常见提示如 ERROR: unterminated quoted string 或 unclosed quotation mark。
手动拼接时必须用两个单引号 '' 转义
SQL 标准规定:字符串内要表示一个字面单引号,必须写成连续两个 ASCII 单引号 '',不是 \',也不是双引号包裹。
-
INSERT INTO logs (msg) VALUES ('User ''admin'' logged in');→ 存入的是User 'admin' logged in -
WHERE title = 'It''s a test';→ 正确匹配It's a test - 三个单引号
'''abc'''是因为外层一对界定字符串,中间一对表示字面单引号:即'+'+abc+'+' - MySQL 默认允许
\',但仅在NO_BACKSLASH_ESCAPES关闭时生效;PostgreSQL 默认不认\',除非关掉standard_conforming_strings(已废弃)
参数化查询才是生产环境唯一可靠方案
手动替换 ' → '' 极易漏逻辑分支或编码不一致,且无法防御 SQL 注入。真正安全的做法是交由驱动处理绑定值,完全跳过 SQL 解析阶段。
- Python + psycopg2:
cursor.execute("SELECT * FROM users WHERE name = %s", ["O'Connor"]) - Java + JDBC:
preparedStatement.setString(1, "O'Connor"); - Node.js + pg:
client.query("SELECT * FROM users WHERE name = $1", ["O'Connor"]) - 哪怕传入
"'; DROP TABLE users; --",也不会触发注入,因为值不参与 SQL 文本构建
最容易被绕过的危险场景
ORM 主流程之外的“辅助路径”——比如导出 SQL 脚本、日志条件动态拼接、DBA 手动修复数据、旧系统维护脚本——常常直接字符串拼接,又没走参数化,结果一遇到 Mc’Alister 或 It’s 就查不到、插不进、甚至删错行。
这类地方不写测试、不走 CI、没人 review,恰恰是单引号问题最顽固的藏身地。

















