在 Oracle 中使用 Regex_substr 到 select 字符串,直到最后一次出现的 space 在 \n 个字符长度内

Using Regex_substr in Oracle to select string up to the last occurence of a space within \n characters length

我们遇到一个问题,我们的 Oracle 数据库中的列的字符长度比另一个系统中的字段长。

因此,我尝试将 case 语句与 substr 一起使用,以拆分长度超过 40 个字符的字符串。到目前为止,我的案例陈述做了我希望他们做的事情,因为它将字符串的前 40 个字符留在 column_a 中,然后将字符串的其余部分放在 column_b 中。

但是,我遇到的问题是,仅使用 substr,字符串会在单词中途被拆分。

所以我想知道是否有人知道我可以与 regex_substr 一起使用的几个正则表达式 -

  1. select 40 个字符以内的最后一个 space 字符串 - 对于 column_a
  2. select 最后一个 space 之后的字符串,在 40 个字符内 - 对于 column_b

这些是我到目前为止对 substr 的案例陈述:

CASE WHEN Length(column_a) > 10 THEN SubStr(column_a, 0, 40) END AS column_a,

CASE WHEN Length(column_a) > 40 THEN SubStr(addressnum, 41) END AS column_b

我完全不熟悉正则表达式,因此非常感谢任何帮助!

我已经用 instr/substr 解决了:

select substr(column_a,1,instr(substr(column_a,1,40), ' ', -1 )) column1,
       substr(column_a,instr(substr(column_a,1,40), ' ', -1 )+1, 40) column2  
from table1

今天在 OTN 上发布了一个非常相似的问题。 https://community.oracle.com/message/13928697#13928697

我发布了一个通用的解决方案,它也将涵盖这里提出的问题。以后有类似的需求说不定能派上用场

对于这里发布的问题,row_lengths table 将只有一行,r_id = 1r_len = 40。出于演示目的,我在下方显示了与我在 OTN 上使用的不同的 input_strings

设置:

create table input_strings (str_id number, txt varchar2(500));

insert into input_strings values (1,
    'One Hundred Sixty-Nine Thousand Eight Hundred Seventy-Four Dollars And Nine Cents');
insert into input_strings values (2, null);
insert into input_strings values (3, 'Mathguy rules');

create table row_lengths (r_id number, r_len number);

insert into row_lengths values (1, 40);

commit;

select * from input_strings;

 STR_ID TXT
------- ---------------------------------------------------------------------------------
      1 One Hundred Sixty-Nine Thousand Eight Hundred Seventy-Four Dollars And Nine Cents
      2
      3 Mathguy rules

3 rows selected

select * from row_lengths;

   R_ID      R_LEN
------- ----------
      1         40

1 row selected.

查询和输出:(注意:我包括令牌长度以验证第一个令牌不超过 40 个字符。如果第二个令牌可以更多,OP 没有回答超过 40 个字符;如果不能,可以将行添加到 row_lengths table,也许每一行都添加 r_len = 40。)

with
     r ( r_id, r_len ) as (
       select r_id         , r_len from row_lengths union all
       select max(r_id) + 1, 4000  from row_lengths union all
       select max(r_id) + 2, null  from row_lengths
     ),
     b (str_id, str, r_id, token, prev_pos, new_pos) as (
       select str_id, txt || ' ', -1, null, null, 0 
         from input_strings
       union all
       select b.str_id, b.str, b.r_id + 1, 
              substr(str, prev_pos + 1, new_pos - prev_pos - 1), 
              b.new_pos, 
              new_pos + instr(substr(b.str, b.new_pos + 1, r.r_len + 1) , ' ', -1)
         from b join r
                on b.r_id + 2 = r.r_id           
     )
select   str_id, r_id, token, nvl(length(token), 0) as len
from     b
where    r_id > 0
order by str_id, r_id;

 STR_ID    R_ID TOKEN                                                LEN
------- ------- ------------------------------------------------ -------
      1       1 One Hundred Sixty-Nine Thousand Eight                 37
      1       2 Hundred Seventy-Four Dollars And Nine Cents           43
      2       1                                                        0
      2       2                                                        0
      3       1 Mathguy rules                                         13
      3       2                                                        0

6 rows selected.