游客发表
在 Oracle 里写 SQL,单引只要字符串里出现单引号,号转就必须转义。单引不转义,号转语句直接报错。单引这个规则简单到几乎不用记,号转但真到了写动态 SQL、单引拼接条件、号转处理用户输入的单引时候,踩坑的号转人一抓一大把。
我见过最典型的单引一次,是号转同事在 PL/SQL 里拼一个查询条件,字段值是单引 O'Brien。他直接写成 WHERE name = 'O'Brien',号转Oracle 解析到第二个单引号就认为字符串结束了,单引剩下的 Brien' 被当成非法标识符,报 ORA-00933。他盯着屏幕愣了半分钟,然后问我:“这单引号怎么这么难搞?”
Oracle 没有反斜杠转义。不像 JavaScript 里可以写 \',也不像 MySQL 默认用 \' 也能跑。Oracle 只认一种写法:把单引号写成两个单引号。
SELECT 'O''Brien' FROM dual; 结果就是 O'Brien。注意,是两个单引号,不是双引号。双引号在 Oracle 里是给标识符用的,比如建表时字段名想区分大小写,写 "MyColumn"。拿双引号包字符串,Oracle 会把它当成列名或别名,直接报错。
这个规则在字符串拼接里同样适用。比如:
SELECT 'It''s a test' FROM dual; 输出 It's a test。如果字符串结尾本身就是一个单引号,写法是四个单引号:''''。第一个和第四个是字符串的边界,中间两个是转义后的单引号。看起来像一堆引号在打架,但 Oracle 就是这么解析的。
静态 SQL 里手动写两个单引号,问题不大。一旦用 EXECUTE IMMEDIATE 或者 DBMS_SQL 拼动态语句,转义层数会叠加。
假设你要拼一个条件:name = 'O''Brien'。在 PL/SQL 里,这个字符串本身又要被单引号包起来,于是变成:
v_sql := 'SELECT * FROM users WHERE name = ''O''''Brien'''; 数一下,O 后面是四个单引号,Brien 后面是三个单引号加一个字符串结束符。第一次写这种语句,基本靠数引号,数着数着就乱了。我的习惯是,先在 SQL*Plus 里把最终要执行的语句写对,再把它塞进 PL/SQL 字符串里,逐层加引号。别靠脑子记,靠编辑器高亮。
如果条件值来自用户输入或程序变量,别拼字符串。用绑定变量:
EXECUTE IMMEDIATE 'SELECT * FROM users WHERE name = :1' USING v_name; 这样 v_name 里有多少单引号都不用管,Oracle 自己处理。既避免了转义错误,也防了 SQL 注入。我见过不少老系统,动态 SQL 里全是 REPLACE 手动替换单引号,代码又长又脆。换成绑定变量,维护量直接降一半。
Oracle 还提供 q 引号语法,适合字符串里单引号特别多的情况。写法是 q'[字符串内容]',方括号可以换成其他成对符号,比如 q'{ ...}'、q'(...)'、q'<...>'。
SELECT q'[It's O'Brien's book]' FROM dual; 输出 It's O'Brien's book。里面的单引号完全不用转义。这个语法在写包含大量单引号的文本时特别舒服,比如生成 JSON 或者 HTML 片段。不过 q 引号不能用在所有地方,比如数据字典视图的某些字段里就不支持。日常 SQL 里用用没问题。
我个人的习惯:普通短字符串,直接两个单引号;长文本或者单引号密集的,用 q 引号;动态 SQL 里,优先绑定变量。别跟单引号硬碰硬, Oracle 的解析器不跟你讲情面。
```友情链接