ORACLE SQL 单引号双重角色

本文参考:http://www.cnblogs.com/mingal/archive/2008/06/04/967782.html
ORACLE SQL 单引号双重角色

今天在项目中遇到动态拼sql的语句,
语句如下:
v_sql := 'update Table_Test t '
||' set t.field1 = ''' || 变量1 || ''',' -- v_BalRuleID || v_BalanceSeq || ''','
||' t.field2 = ''' || 变量2 || ''','
||' t.field3 = ''' || 变量3 || ''','
||' t.field4 = 1,'
||' t.field5 = ' || 变量4
||' where t.field6 = ''' || 变量5 || ''''
||' and INSTRb( '''|| 变量6 ||''',t.field7 ) >0 ';
execute immediate v_sql;

单引号双重角色——字符串引用与转义

在ORACLE中,单引号有两个作用,一是字符串是由单引号引用,二是转义,开始学习时动态构成SQL时经常不解。单引号的使用是就近配对,即就近原则。而在单引号充当转义角色时相对不好理解。
1、从第二个单引号开始被视为转义符,如果第二个单引号后面还有单引号(哪怕只有一个)。
SQL> SELECT '''' FROM DUAL;

''
--
'

为了证实结果是被第二个单引号转义的第三个单引号(既:SELECT '''' FROM DUAL;),我们做如下两个测试:

SQL> SELECT ''' FROM DUAL;
ERROR:
ORA-01756: 括号内的字符串没有正确结束



相信大家对这样的错误不陌生吧

SQL> SELECT 'SDLF FROM DUAL;
ERROR:
ORA-01756: 括号内的字符串没有正确结束

也就是说,当第二个单引号充当转义角色,第三个单引号被转义,(既:select '' ' from dual;)自然就缺少与第一个单引号匹配的单引号了,出现了孤立的单引号
下面的两个实验就更加支持了上面的结论。

SQL> SELECT ' '' ' FROM DUAL;

''''
------
'

SQL> SELECT '' '' FROM DUAL;
SELECT '' '' FROM DUAL
*
ERROR 位于第 1 行:
ORA-00923: 未找到预期 FROM 关键字



对于第一个:SELECT ' '' ' FROM DUAL;
对于第二个:不存在转义。

上面的这两个实验其实也是单引号转义与非转义的一个性质:转义是密集的,也就是说,如果单引号出现在转义的位置上,而该单引号后面紧跟(紧跟的定义为:两个单引号之间是零距离的)的不是单引号,这个时候单引号就不在充当转义的角色,而是与它前面的配对。

2、连接符‘||’导致了新一轮的转义:连接符号‘||’左右的单引号没有任何的关系,除非‘||’是作为字符串的一部分(这在动态SQL中很常见)。

SQL> SELECT 'ORACLE'||'''' FROM DUAL;

'ORACLE'||''
----------
ORACLE'
个人理解,'ORACLE'||'''' 后面的“''''”应该认为是一个字符串(即前后单引号,中间是“''”串,而中间又是密集单引号,因此第一个为转义功能)
SQL> SELECT 'ORACLE''''' FROM DUAL;

'ORACLE'''''
------------
ORACLE''
对于第一个,前两个单引号配对,后面四个单引号按照上面的第一条原则分配,既:SELECT 'ORACLE'||'''' FROM DUAL;
对于第二个,由于第二个单引号后面存在单引号,所以就不与第一个配对,而是充当了转义的角色。既:SELECT 'ORACLE''''' FROM DUAL;

有了上面的两条原则,我们就可以从容的面对复杂的动态SQL了。
<think>我们正在讨论的是在SQL中使用正则表达式时的转义符问题。根据引用[1]和[2],SQL中的正则表达式功能通常通过特定函数(如REGEXP_LIKE,REGEXP_REPLACE等)来实现。但是,不同数据库系统(如MySQL,Oracle,PostgreSQL)对正则表达式的支持程度和转义规则可能有所不同。下面我将以常见的数据库系统为例,解释转义符的用法。###通用规则1.**转义特殊字符**:在正则表达式中,特殊字符(如`.*+?^$[](){}|\`)需要转义才能匹配字面值。转义的方法是使用反斜杠`\`。-例如:匹配字符串中的点号`.`,正则表达式应写为`\.`。2.**SQL字符串转义**:在SQL语句中,字符串本身也有转义规则(例如,在MySQL中,字符串内的反斜杠通常需要写成两个反斜杠`\\`,除非设置了`NO_BACKSLASH_ESCAPES`模式)。3.**双重转义问题**:由于正则表达式在SQL字符串中书写,因此可能需要双重转义:-在正则表达式中表示一个反斜杠需要写`\\`。-在SQL字符串中,每个反斜杠又需要转义,所以最终可能写成`\\\\`。###不同数据库的示例####MySQL示例在MySQL中,使用`REGEXP`或`RLIKE`进行正则匹配。默认情况下,MySQL会解释字符串中的转义序列,因此正则表达式的反斜杠需要写成两个反斜杠。```sql--匹配包含小数点的数字SELECT*FROMproductsWHEREproduct_nameREGEXP'\\d+\\.\\d+';```解释:正则表达式原本应为`\d+\.\d+`,但在SQL字符串中,每个`\`都需要写成`\\`,所以变成`\\d+\\.\\d+`。如果使用`REGEXP_LIKE`函数(MySQL8.0+),同样适用:```sqlSELECT*FROMproductsWHEREREGEXP_LIKE(product_name,'\\d+\\.\\d+');```####Oracle示例Oracle中使用`REGEXP_LIKE`等函数,其转义规则与MySQL类似,但Oracle允许使用转义子句指定转义字符。```sql--使用默认转义字符(反斜杠)SELECT*FROMproductsWHEREREGEXP_LIKE(product_name,'\d+\.\d+');```注意:在Oracle中,如果正则表达式中含有反斜杠,在SQL字符串中只需写一个反斜杠,因为Oracle不默认解释字符串中的反斜杠转义(除非使用`CHR`函数等)。但是,如果字符串中包含单引号,则需要用两个单引号表示。另外,Oracle允许自定义转义字符:```sqlSELECT*FROMproductsWHEREREGEXP_LIKE(product_name,'\d+\.\d+','c');--'c'表示区分大小写,转义字符默认为反斜杠--自定义转义字符为'/'SELECT*FROMproductsWHEREREGEXP_LIKE(product_name,'\d+\.\d+','c','/');```####PostgreSQL示例PostgreSQL的正则表达式功能强大,使用`~`操作符或`regexp_match`等函数。在PostgreSQL中,字符串中的反斜杠转义默认是关闭的(除非使用`E''`字符串)。```sql--使用普通字符串(不需要双重转义)SELECT*FROMproductsWHEREproduct_name~'\d+\.\d+';--如果使用E''字符串(开启转义),则需要双重转义SELECT*FROMproductsWHEREproduct_name~E'\\d+\\.\\d+';```###特殊转义场景:匹配反斜杠本身如果需要在正则表达式中匹配反斜杠字符`\`,则:-正则表达式需要写为`\\`(表示一个字面上的反斜杠)。-在SQL字符串中,每个反斜杠都需要转义,所以最终写为`\\\\`(MySQL)或`\\`(Oracle、PostgreSQL普通字符串)。**示例(MySQL)**:匹配包含反斜杠的路径```sqlSELECT*FROMpathsWHEREpathREGEXP'\\\\';--匹配包含至少一个反斜杠的路径```###使用ESCAPE子句(部分数据库支持)一些数据库的正则表达式函数允许指定转义字符。例如,在Oracle中,可以在`REGEXP_LIKE`的第四个参数指定转义字符。###总结1.**基本规则**:在正则表达式中用`\`转义特殊字符。2.**数据库差异**:-MySQLSQL字符串中需要双重转义(`\\`变为`\\\\`)。-Oracle:通常只需单重转义,但可通过转义子句自定义。-PostgreSQL:默认字符串不转义反斜杠,所以正则中写一个`\`即可;若用`E''`字符串则需双重转义。3.**最佳实践**:测试特定数据库的转义行为,或使用函数参数指定转义字符(如Oracle)。>注意:具体数据库版本可能有差异,请参考官方文档[^1][^2][^3]。§§相关问题§§1.在MySQL中如何匹配包含方括号`[]`的字符串?2.如何在Oracle的正则表达式中使用自定义转义字符?3.PostgreSQL中`E''`字符串和普通字符串在正则表达式中的区别是什么?</think>### SQL 正则表达式转义符用法详解 在 SQL 中使用正则表达式时,**反斜杠 `\`** 是主要的转义字符,用于处理特殊字符的匹配。不同数据库系统的实现有所差异,以下是核心规则和示例: --- #### 一、通用转义规则 1. **转义特殊字符** 需转义的正则特殊字符包括:`. * + ? ^ $ [ ] ( ) { } | \` ```sql -- 匹配含点号的价格(如 "5.99") SELECT * FROM products WHERE product_name REGEXP '\\d+\\.\\d+'; -- 转义点号[^1] ``` 2. **匹配字面反斜杠** 由于 SQL 字符串和正则的双重转义,需写四个反斜杠: ```sql -- 匹配 Windows 路径(如 "C:\Windows") SELECT * FROM paths WHERE path REGEXP 'C:\\\\Windows'; -- 实际匹配一个反斜杠[^3] ``` --- #### 二、数据库差异实现 1. **MySQL** 使用 `REGEXP` 或 `RLIKE`,需双重转义: ```sql -- 匹配含问号的URL参数 SELECT * FROM urls WHERE url REGEXP '\\?id='; -- 转义问号[^2] -- 检查是否包含数字 SELECT 'price: $5' REGEXP '\\d'; -- 返回 1(包含数字)[^3] ``` 2. **Oracle** 使用 `REGEXP_LIKE` 函数,支持自定义转义符: ```sql -- 匹配含括号的文本 SELECT * FROM docs WHERE REGEXP_LIKE(content, '\(重要\)', 'c'); -- 'c'表示区分大小写 -- 自定义转义符为'!' SELECT REGEXP_REPLACE('10*20', '!\*', '+') FROM dual; -- 结果 "10+20" ``` 3. **PostgreSQL** 使用 `~` 操作符,支持单次转义: ```sql -- 匹配邮箱中的点号 SELECT * FROM users WHERE email ~ 'user\.name@'; -- 单反斜杠转义点号 ``` --- #### 三、实用场景示例 1. **提取带小数点的数字** ```sql -- MySQL示例 SELECT REGEXP_SUBSTR('Total: 42.5 kg', '\\d+\\.\\d+') AS value; -- 结果 "42.5" ``` 2. **替换特殊字符** ```sql -- Oracle示例 SELECT REGEXP_REPLACE('file[name].txt', '[\\[\\]]', '_') FROM dual; -- 结果 "file_name_.txt" ``` 3. **验证复杂格式** ```sql -- 检查是否包含非法字符(如 & 或 ?) SELECT CASE WHEN 'user@test?com' REGEXP '[\\?\\&]' THEN 'invalid' ELSE 'valid' END; ``` --- ### 关键注意事项 1. **双重转义必要性** 在 MySQL 等数据库中,SQL 字符串先解析一次转义,正则引擎再解析一次,因此需写 `\\` 表示正则的一个 `\`。 2. **原始字符串替代方案** 部分数据库(如 PostgreSQL)支持 `E'\\d'` 语法避免双重转义: ```sql SELECT * FROM logs WHERE msg ~ E'\\d{3}-\\d{4}'; -- 匹配电话号码 ``` 3. **性能影响** 复杂正则表达式(尤其是带多重转义)可能影响查询性能,建议先过滤再正则匹配[^1]。 > **最佳实践**: > 1. 优先查阅数据库官方文档(如 MySQL 的 `REGEXP` 或 Oracle 的 `REGEXP_LIKE`) > 2. 使用 `REGEXP_REPLACE()` 函数测试转义效果 > 3. 对用户输入的正则做安全过滤[^2] ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值