Oracle、Regexp、用分号分隔的字符串

Posted

技术标签:

【中文标题】Oracle、Regexp、用分号分隔的字符串【英文标题】:Oracle, Regexp, string separated via semicolons 【发布时间】:2017-12-20 11:55:09 【问题描述】:

我有这个查询:

SELECT ROWNUM AS num_row,
       REGEXP_SUBSTR(REPLACE('param1;param2;param3;;param5;;param7;;;param10;param11;param12;param13;param14;param15;',
                             ';;',
                             '; ;'),
                     '[^;]+',
                     1,
                     level) AS par_value
FROM   dual
CONNECT BY REGEXP_SUBSTR(REPLACE('param1;param2;param3;;param5;;param7;;;param10;param11;param12;param13;param14;param15;',
                                 ';;',
                                 '; ;'),
                         '[^;]+',
                         1,
                         level) IS NOT NULL

输出:

1   param1
2   param2
3   param3
4    
5   param5
6    
7   param7
8    
9   param10
10  param11
11  param12
12  param13
13  param14
14  param15

正如您已经看到(或未看到),在参数 7 和 10 之间应该有两个 NULL 参数,但是这个查询只返回一个。

如果我在 'param10' 之前多放一个分号或将 ';;param10' 更改为 '; ;param10' -> param10 在第 10 行,但这是我做不到的。

似乎';'的序列更长oracle 总是把分号的数量视为 -1 。

有人知道如何解决吗?

【问题讨论】:

仅供参考,这些是分号。 : 是一个冒号。 仅供参考,感谢您的回答。真的有帮助:) 我想每个人都会理解这个问题 【参考方案1】:

如果我是你,我会通过在 connect by 子句中使用 regexp_count 来简化事情(看起来你的参数总是以分号结尾,所以无论有多少分号,你都想遍历字符串很多次)。

另外,[^<characters>] 的方法不处理空值,因此您需要切换到(.*?)(;|$) 的模式 - 即。零个或多个字符后跟一个分号,然后只选择第一个表达式 (`.*?)。

这意味着你可以这样做:

WITH sample_data AS (SELECT 'param1;param2;param3;;param5;;param7;;;param10;param11;param12;param13;param14;param15;' str FROM dual)
SELECT LEVEL AS num_row,
       REGEXP_SUBSTR(REPLACE(str,
                             ';;',
                             '; ;'),
                     '[^;]+',
                     1,
                     level) AS par_value,
       REGEXP_SUBSTR(str, '(.*?)(;)', 1, LEVEL, NULL, 1) new_str
FROM   sample_data
CONNECT BY LEVEL <= regexp_count(str, ';');

   NUM_ROW PAR_VAL NEW_STR
---------- ------- -------
         1 param1  param1
         2 param2  param2
         3 param3  param3
         4         
         5 param5  param5
         6         
         7 param7  param7
         8         
         9 param10 
        10 param11 param10
        11 param12 param11
        12 param13 param12
        13 param14 param13
        14 param15 param14
        15         param15

注意,如果尾随分号实际上意味着后面有一个空参数,那么您需要切换到(.*?)(;|$) 的模式(即零个或多个字符后跟分号或结尾字符串),另外你需要在 regexp_count 结果中加一:

WITH sample_data AS (SELECT 'param1;param2;param3;;param5;;param7;;;param10;param11;param12;param13;param14;param15;' str FROM dual)
SELECT LEVEL AS num_row,
       REGEXP_SUBSTR(REPLACE(str,
                             ';;',
                             '; ;'),
                     '[^;]+',
                     1,
                     level) AS par_value,
       REGEXP_SUBSTR(str, '(.*?)(;|$)', 1, LEVEL, NULL, 1) new_str
FROM   sample_data
CONNECT BY LEVEL <= regexp_count(str, ';') + 1;

   NUM_ROW PAR_VAL NEW_STR
---------- ------- -------
         1 param1  param1
         2 param2  param2
         3 param3  param3
         4         
         5 param5  param5
         6         
         7 param7  param7
         8         
         9 param10 
        10 param11 param10
        11 param12 param11
        12 param13 param12
        13 param14 param13
        14 param15 param14
        15         param15
        16         

【讨论】:

以上是关于Oracle、Regexp、用分号分隔的字符串的主要内容,如果未能解决你的问题,请参考以下文章

使用 regexp_substr 在 Oracle 中按空格和字符拆分字符串作为分隔符

Oracle Regexp 根据第一次出现的分隔符拆分字符串

Oracle REGEXP_SUBSTR |获取两个分隔符之间的字符串

Oracle SQL REGEXP 用不同的列值替换特定字符串

REGEXP oracle几个not语句

CustomActionData 用分号分隔,导致字符串溢出 - 此解决方案的常见解决方法是啥?