检查SQL中字符串中是否存在字符的最佳方法是什么?

时间:2014-06-03 12:31:39

标签: sql regex oracle

我有像:

这样的字符串
t.reported_name
-------------------------
    D3O using TM-0549 - Rev # 6
    D3O using TM-0549 - Rev # 6
    Water using TM-0415 - Rev #10
    Water using TM-0449 - Rev # 10
    Decanoic Acid using LL-1448 - Rev# 2
    DBE-821 using QCRM-0015 - Rev#1
    Water using TM-0441 Rev # 10
    FC Sessile Drop Contact Angle using MTM-017_REV_B - Rev # 1
    IPA using QCRM-0017
    Norbloc using TM-0501 - Rev # 5
    DK (non-edge corrected) using TM-0534 - Rev # 3
    Decanoic Acid_L3 using LL-1448_L3
    Decanoic Acid_L4 using LL-1448_L4
    MXP7-1911 using CRM-0239
    TMPTMA using TM-0515 - Rev# 8
    DK (edge corrected) using MTM-09 - Rev# 0

我需要提取测试方法(使用'之后的任何内容)和数字,即:TM-0549 和修订号,即:Rev # 6

select  distinct 
     case when REGEXP_LIKE(t.reported_name,'TM-', 'c') THEN SUBSTR(t.reported_name, INSTR(t.reported_name, 'TM'), 7) END test_method,
     case when INSTR(t.reported_name,'Rev #') = 1 THEN SUBSTR(t.reported_name, INSTR(t.reported_name, 'Rev'), 7) END revision_number
from test s

从我想要的数据:

test_method  revision_number

TM-0549     Rev # 6
TM-0549     Rev # 6
TM-0415     Rev #10
TM-0449     Rev # 10
LL-1448     Rev# 2
QCRM-0015   Rev#1
TM-0441     Rev # 10
MTM-017_REV_B  Rev # 1
QCRM-0017   null
TM-0501     Rev # 5
TM-0534     Rev # 3
LL-1448_L3  null
LL-1448_L4  null
CRM-0239    null
TM-0515     Rev# 8
MTM-09      Rev# 0

3 个答案:

答案 0 :(得分:1)

TMPTMA与正则表达不匹配,instr正在运行:

select 'regexp match' descr, count(*) 
from dual where regexp_like('TM-PTMA', 'TM-') 
union all
select 'regexp no match', count(*) 
from dual where regexp_like('TMPTMA', 'TM-') 
union all
select 'instr no match', count(*) 
from dual where instr('TMPTMA', 'TM-') > 0
union all
select 'instr match', count(*) 
from dual where instr('TM-PTMA', 'TM-') > 0

输出:

DESCR             COUNT(*)
--------------- ----------
regexp match             1 
regexp no match          0 
instr no match           0 
instr match              1 

答案 1 :(得分:1)

假设

  • 对于test_method,我们希望匹配TM-<number>
  • 进行修订,我们希望匹配Rev # <number>(请注意#周围的空格)

然后这是REGEXP_SUBSTR的解决方案:

select 
  regexp_substr(reported_name, 'TM\-[0-9]+') as test_method_regexsub,
  regexp_substr(reported_name, 'Rev # [0-9]+') as revision_regexsub            
from test t

这是另一个REGEXP_REPLACE;如果正则表达式不匹配,我们必须使用CASE / REGEXP_LIKE变通方法返回空字符串,因为如果找不到匹配项,REGEXP_REPLACE将返回整个字符串:

select 
  (case 
     when regexp_like(reported_name, '.*(TM\-[0-9]+).*') 
     then regexp_replace(reported_name, '.*(TM\-[0-9]+).*', '\1') 
     else '' 
   end)  as test_method_regexrepl,
  (case 
     when regexp_like(reported_name, '.*(Rev # [0-9]+).*') 
     then regexp_replace(reported_name, '.*(Rev # [0-9]+).*', '\1') 
     else '' 
   end)  as revision_regexrepl
from test t

第二种方法使用捕获组(Rev # [0-9]+)并将整个字符串替换为其内容\1

第二次更新

假设

  • using前面的所有内容都应该被忽略
  • 可选Rev的所有内容都是测试方法名称
  • 修订版由Rev # <number>组成,其中第一个空格是可选的

这应该有效:

select reported_name,
       (case 
          when regexp_like(reported_name, '.* using (.*)( - Rev.*)') 
            then regexp_replace(reported_name, '.* using (.*)( - Rev.*)', '\1') 
          when regexp_like(reported_name, '.* using (.*)') 
            then regexp_replace(reported_name, '.* using (.*)', '\1') 
          else '' end)  as test_method_regexrepl,
       (case when regexp_like(reported_name, '.* - (Rev[ ]?# [0-9]+)') 
          then regexp_replace(reported_name, '.*(Rev[ ]?# [0-9]+)', '\1') 
          else '' end)  as revision_regexrepl
from test t

说明:

  • .* using (.*)( - Rev.*)是我们对具有修订版的测试方法的正则表达式。匹配

    • 任意字符串.*
    • 字符串using(注意两个空格)
    • 任意字符串(.*) - 我们使用括号()来捕获组中匹配的这一部分
    • 字符串- Rev,后跟任意字符串;再次,我们使用括号来捕获组中的字符串(虽然我们并不真的需要)

    如果匹配,我们会将整个字符串替换为第一个捕获组\1(这包含usingRev之间的部分

  • .* using (.*)是我们对没有修订版的测试方法的回退;匹配

    • 任意字符串.*
    • 字符串using(注意两个空格)
    • 任意字符串(.*) - 我们使用括号()来捕获组中匹配的这一部分

    如果匹配,我们会将整个字符串替换为第一个捕获组\1(这包含usingRev之间的部分

  • .* - (Rev[ ]?# [0-9]+)是修订部分的正则表达式。匹配

    • 一个任意字符串后跟一个由空格.* -
    • 包围的连字符
    • 单词Rev
    • 可选空格[ ]?
    • 格子后跟空格#
    • 一个或多个数字[0-9]+ 并再次使用捕获组(Rev...)作为“有趣”部分

    如果匹配,我们将整个字符串替换为第一个捕获组\1(这包含Rev和最后一个数字之间的部分)

SQL Fiddle

答案 2 :(得分:1)

至于我的特殊情况查询可以看起来像:

WITH j
     AS (SELECT 'D3O using TM-0549 - Rev # 6' str FROM DUAL
         UNION ALL
         SELECT 'D3O using TM-0549 - Rev # 6' FROM DUAL
         UNION ALL
         SELECT 'Water using TM-0415 - Rev #10' FROM DUAL
         UNION ALL
         SELECT 'Water using TM-0449 - Rev # 10' FROM DUAL
         UNION ALL
         SELECT 'Decanoic Acid using LL-1448 - Rev# 2' FROM DUAL
         UNION ALL
         SELECT 'DBE-821 using QCRM-0015 - Rev#1' FROM DUAL
         UNION ALL
         SELECT 'Water using TM-0441 Rev # 10' FROM DUAL
         UNION ALL
         SELECT 'FC Sessile Drop Contact Angle using MTM-017_REV_B - Rev # 1' FROM DUAL
         UNION ALL
         SELECT 'IPA using QCRM-0017' FROM DUAL
         UNION ALL
         SELECT 'Norbloc using TM-0501 - Rev # 5' FROM DUAL
         UNION ALL
         SELECT 'DK (non-edge corrected) using TM-0534 - Rev # 3' FROM DUAL
         UNION ALL
         SELECT 'Decanoic Acid_L3 using LL-1448_L3' FROM DUAL
         UNION ALL
         SELECT 'Decanoic Acid_L4 using LL-1448_L4' FROM DUAL
         UNION ALL
         SELECT 'MXP7-1911 using CRM-0239' FROM DUAL
         UNION ALL
         SELECT 'TMPTMA using TM-0515 - Rev# 8' FROM DUAL
         UNION ALL
         SELECT 'DK (edge corrected) using MTM-09 - Rev# 0' FROM DUAL)

SELECT TRIM(RTRIM(TRIM (SUBSTR (clear_str, 0, INSTR (clear_str, ' ') + LENGTH (' '))),'-')) AS left_str,
       TRIM(LTRIM(TRIM (SUBSTR (clear_str, INSTR (clear_str, ' ') + LENGTH (' '))),'-')) AS right_str
  FROM (SELECT TRIM (SUBSTR (str, INSTR (str, 'using') + LENGTH ('using'))) || ' ' clear_str FROM j)

<强> UPD。 此外,此解决方案不依赖于商业数据,如&#39; Rev&#39;或者是其他东西。但它对test_method值

中的空格很敏感