从Oracle SQL中的字符串中提取值

时间:2019-04-27 05:58:08

标签: sql regex oracle

我正在从Oracle的描述字段中提取可能的值。他们有成千上万,我想到了使用SQL来做。

问题在于可能的值会在说明中嵌入“可接受的值:”或“可接受的值:”之后。

此外,这些值还包含代码和说明,例如。

00 =无代码

01 =附加代码

我需要提取可能的值。

这在Oracle表中。

这是源表:

表1

VAR_NAME    VAR_DESC
Test 1      Code identifying test 1
            Acceptable values:
            00=No code
            01=Additional Code

Test 2      Code identifying test 2
            Acceptable value:
            44=No code

这是输出表:

VAR_NAME    VAR_DESC                    CODE        DESCRIPTION
Test 1      Code identifying test 1     00          No code
            Acceptable values:
            00=No code
            01=Additional Code

Test 1      Code identifying test 1     01          Additional Code
            Acceptable values:
            00=No code
            01=Additional Code


Test 2      Code identifying test 2     44          No code
            Acceptable value:
            44=No code  

Oracle中是否有一种方法可以提取此类信息?

2 个答案:

答案 0 :(得分:1)

您可以同时使用regexp_countregexp_instr。关键字符为=和回车符(chr(10)),如下所示:

with table1(var_name,var_desc) as
(
 select 'Test 1',
        'Code identifying test 1
         Acceptable values:
         00=No code
         01=Additional Code' from dual union all
 select 'Test 2',
        'Code identifying test 2
         Acceptable value:
         44=No code'         from dual union all
 select 'Test 3',
        'Code identifying test 3' 
                             from dual       
), table2(var_name,str1,description) as
(
 select var_name,
        case when regexp_count(var_desc,chr(10)) > 0 then
             regexp_substr(var_desc,'[^=]+',regexp_instr(var_desc,chr(10), 1, level))
        end,
        case when regexp_count(var_desc,chr(10)) > 0 then
             regexp_substr(var_desc,'=(.*)+',regexp_instr(var_desc,chr(10), 1, level))
        end 
   from table1
connect by level <= regexp_count(var_desc,chr(10)) 
    and prior var_name = var_name
    and prior sys_guid() is not null   
)    
select t1.*, 
      decode(regexp_count(str1,chr(10)),1,str1) as code, ltrim(str2,'=') as description
 from table2 t2
 join table1 t1 on t1.var_name = t2.var_name
where decode(regexp_count(str1,chr(10)),1,str1) is not null
order by t1.var_name, code;

VAR_NAME    VAR_DESC                 CODE   DESCRIPTION
--------    -----------------------  ----   -----------
Test 1      Code identifying test 1  00     No code
            Acceptable values:
            00=No code
            01=Additional Code

Test 1      Code identifying test 1  01     Additional Code
            Acceptable values:
            00=No code
            01=Additional Code

Test 2      Code identifying test 2  44     No code
            Acceptable value:
            44=No code

Demo

答案 1 :(得分:0)

其中之一是使用字符串函数。这是带有说明的示例方法。

with source_table as (select 
'Code identifying test 1
Acceptable values:
00=No code
01=Additional Code'  val
from dual)
select substr(val, instr(val, chr(10), 1, 2)+1 ,2) code
,substr(val, instr(val, '=', instr(val,chr(10), 1, 2), 1)+1 ,  (  instr(val,chr(10), 1, 3) - instr(val,'=', 1, 1)  ) ) description
from source_table;

说明

第1步:使用数据创建表:我不是使用临时表并添加测试数据,而是使用 WITH 子句来欺骗表的创建。在这种情况下,我创建了一个名称为 source_table 的表,该表具有一列 val 。它有一行数据,它是source_table第1行中 VAR_DESC 列中的值。您不需要这样做,因为您已经有一个数据库中包含数据的表。

with source_table as (select 
'Code identifying test 1
Acceptable values:
00=No code
01=Additional Code'  val
from dual)

现在用于实际的字符串提取。 INSTR 查找子字符串在字符串中的位置。 SUBSTR 从字符串中提取一个子字符串。因此,我要做的是,我试图确定您数据中的模式。要提取的第一个数据点位于第二个换行符(chr(10))字符之后。一旦有了这个位置,我就从这一点开始提取长度为2的子字符串。下一个要提取的子字符串在第一个 = 字符之后开始,其长度已计算为第四个 newline 字符与第一个字符之间的位置差 = 个字符。

同样,如果需要在同一行源数据中提取多行字符串,则需要应用类似的逻辑。

更简单的方法是利用Oracle的PL / SQL功能并创建一个函数(该函数在内部将字符串分步拆分),然后在SQL中调用该函数。可以使代码更具可读性。您将在PL / SQL中使用相同的字符串函数。但是您可以执行此步骤,使以后可能需要管理您代码的其他人更容易遵循该代码。