13

我正在使用 Oracle 11g,我想使用 REGEXP_SUBSTR 来匹配给定模式的所有出现。例如

 SELECT
  REGEXP_SUBSTR('Txa233141b Ta233141 Ta233142 Ta233147 Ta233148',
  '(^|\s)[A-Za-z]{2}[0-9]{5,}(\s|$)') "REGEXP_SUBSTR"
  FROM DUAL;

仅返回第一个匹配项 Ta233141,但我想返回与正则表达式匹配的其他匹配项,即 Ta233142 Ta233147 Ta233148。

4

6 回答 6

20

REGEXP_SUBSTR 只返回一个值。你可以把你的字符串变成一个伪表,然后查询它的匹配项。目前有一种基于 XML 的方法让我无法理解,但只要你只有一个源字符串,使用 connect-by 就可以了:

SELECT REGEXP_SUBSTR(str, '[^ ]+', 1, LEVEL) AS substr
FROM (
    SELECT 'Txa233141b Ta233141 Ta233142 Ta233147 Ta233148' AS str FROM DUAL
)
CONNECT BY LEVEL <= LENGTH(REGEXP_REPLACE(str, '[^ ]+')) + 1;

... 给你:

SUBSTR             
--------------------
Txa233141b           
Ta233141             
Ta233142             
Ta233147            
Ta233148            

...您可以使用原始模式的稍微简单的版本对其进行过滤:

SELECT substr
FROM (
    SELECT REGEXP_SUBSTR(str, '[^ ]+', 1, LEVEL) AS substr
    FROM (
        SELECT 'Txa233141b Ta233141 Ta233142 Ta233147 Ta233148' AS str
        FROM DUAL
    )
    CONNECT BY LEVEL <= LENGTH(REGEXP_REPLACE(str, '[^ ]+')) + 1
)
WHERE REGEXP_LIKE(substr, '^[A-Za-z]{2}[0-9]{5,}$');

SUBSTR             
--------------------
Ta233141             
Ta233142             
Ta233147             
Ta233148             

这不是很漂亮,但也不是在一个字段中保存多个值。

于 2013-07-11T15:08:31.143 回答
4

这有点晚了,但我需要基本相同的东西并且找不到好的片段。我需要在表格的自由文本列中搜索一些术语并收集它们。由于这可能对其他人有用,因此我已包含基于此问题的版本。虽然 REGEXP_SUBSTR 只返回一个值,但 Oracle 还提供了 REGEXP_COUNT 来告诉您在给定字符串中存在多少匹配项,因此您可以将其与索引列表连接以选择每个索引,如下所示(此查询中的示例为自由文本来自一些'source_table'):

DEFINE MATCH_EXP = "'(^|\s)[A-Za-z]{2}[0-9]{5,}'"

WITH source_table
     -- Represents some DB table with a 'free_text' column to be checked.
     AS (       ( SELECT 'Txa233141 Ta233141 Ta232 Ta233142 Ta233141 Ta233148'
                             AS free_text FROM dual )
          UNION ( SELECT 'Other stuff PH33399 mixed in OS4456908843 this line'
                             AS free_text FROM dual )
        )
   , source
     -- For some table, select rows of free text and add the number of matches
     -- in the line.
     AS ( SELECT cnt
               , free_text
          FROM ( SELECT RegExp_Count(free_text, &MATCH_EXP) AS cnt
                      , free_text 
                 FROM source_table )
          WHERE cnt > 0 )
   , iota
     -- Index generator
     AS ( SELECT RowNum AS idx
          FROM dual
          CONNECT BY RowNum <= ( SELECT Max(cnt) FROM source ) )
-- Extract the unique 'cnt' matches from each line of 'free_text'.
SELECT UNIQUE
       RegExp_SubStr(s.free_text, &MATCH_EXP, 1, i.idx) AS result
FROM   source s
  JOIN iota i
    ON ( i.idx <= s.cnt )
ORDER BY result ASC
;

它具有适用于任何选定行列表的优点,并且最少使用 CONNECT BY(因为这可能非常慢)。

于 2017-05-10T13:07:52.940 回答
2

添加一个循环并返回所有值的函数怎么样?

create or replace function regexp_substr_mr (
  p_data clob,
  p_re varchar
  )
return varchar as
  v_cnt number;
  v_results varchar(4000);
begin
  v_cnt := regexp_count(p_data, p_re, 1,'m');
  if v_cnt < 25 then
    for i in 1..v_cnt loop
      v_results := v_results || regexp_substr(p_data,p_re,1,i,'m') || chr(13) || chr(10);
    end loop;
  else 
    v_results := 'WARNING more than 25 matches found';
  end if;

  return v_results;
end;

然后只需调用该函数作为选择查询的一部分。

于 2014-05-15T16:10:53.583 回答
1

我修复了@Alex Poole对多行源代码支持和更快执行的回答:

with templates as (select '\w+' regexp from dual)
select 
    regexp_substr(str, templates.regexp, 1, level) substr
from (
    select 1 id, 'Txa233141b Ta233141 Ta233142 Ta233147 Ta233148' as str from dual
    union
    select 2 id, '2 22222222222222Ta233141 2Ta233142 2Ta233147' as str from dual
    union
    select 3 id, '3Txa233141b 3Ta233141 3Ta233142' as str from dual
)
join templates on 1 = 1
connect by 
    id = connect_by_root id
    and regexp_instr(str, templates.regexp, 1, level) > 0
order by id, level

源代码行:

ID  STR                                             
--  ----------------------------------------------  
1   Txa233141b Ta233141 Ta233142 Ta233147 Ta233148  
2   2 22222222222222Ta233141 2Ta233142 2Ta233147    
3   3Txa233141b 3Ta233141 3Ta233142                 

结果:

Txa233141b              
Ta233141                
Ta233142                
Ta233147                
Ta233148                
2                       
22222222222222Ta233141  
2Ta233142               
2Ta233147               
3Txa233141b             
3Ta233141               
3Ta233142               
于 2016-12-09T20:59:44.003 回答
0

基于@David E. Veliev answer,这是多行输入的查询。如果以下查询对您有用,请考虑投票赞成原始答案

SELECT SUBSTR
  FROM (WITH TEMPLATES AS (SELECT '\w+' REGEXP FROM DUAL)
         SELECT ID,
                CONNECT_BY_ROOT ID CBR,
                LEVEL LVL,
                REGEXP_SUBSTR(STR, TEMPLATES.REGEXP, 1, LEVEL) SUBSTR
           FROM (SELECT 1 ID,
                        'Txa233141b Ta233141 Ta233142 Ta233147 Ta233148' AS STR
                   FROM DUAL
                 UNION
                 SELECT 2 ID,
                        '2 22222222222222Ta233141 2Ta233142 2Ta233147' AS STR
                   FROM DUAL
                 UNION
                 SELECT 3 ID,
                        '3Txa233141b 3Ta233141 3Ta233142' AS STR
                   FROM DUAL)
           JOIN TEMPLATES
             ON 1 = 1
         CONNECT BY REGEXP_INSTR(STR, TEMPLATES.REGEXP, 1, LEVEL) > 0)
          WHERE ID = CBR
          GROUP BY ID,
                   CBR,
                   LVL,
                   SUBSTR
          ORDER BY ID,
                   LVL;

输入:

身份证号
== ===============================================
1 Txa233141b Ta233141 Ta233142 Ta233147 Ta233148
2 2 22222222222222Ta233141 2Ta233142 2Ta233147
3 3Txa233141b 3Ta233141 3Ta233142

输出:

SUBSTR
=======================
TXA233141B
Ta233141
Ta233142
Ta233147
Ta233148
2
22222222222222Ta233141
2Ta233142
2Ta233147
3Txa233141b
3Ta233141
3Ta233142
于 2018-11-13T09:53:46.700 回答
-2

以下是您问题的简单解决方案。

SELECT REGEXP_SUBSTR('Txa233141b Ta233141 Ta233142 Ta233147 Ta233148',
  '([a-zA-Z0-9]+\s?){1,}') "REGEXP_SUBSTR"
  FROM DUAL;
于 2015-12-04T19:02:18.757 回答