2013-07-11 38 views
8

Tôi đang sử dụng Oracle 11g và tôi muốn sử dụng REGEXP_SUBSTR để khớp với tất cả các lần xuất hiện cho một mẫu nhất định. Ví dụOracle 11g nhận tất cả các lần xuất hiện phù hợp theo biểu thức chính quy

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

lợi nhuận chỉ là trận đấu đầu tiên Ta233141 nhưng tôi muốn trả lại sự cố khác phù hợp với regex, có nghĩa Ta233142 Ta233147 Ta233148.

Trả lời

15

REGEXP_SUBSTR chỉ trả về một giá trị. Bạn có thể biến chuỗi của bạn thành một bảng giả và sau đó truy vấn cho phù hợp. Có một cách dựa trên XML để làm điều này mà thoát cho tôi vào lúc này, nhưng sử dụng công trình kết nối theo, miễn là bạn chỉ có một chuỗi nguồn:

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; 

... mang đến cho bạn:

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

... và bạn có thể lọc rằng với một phiên bản hơi đơn giản của mô hình ban đầu của bạn:

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    

đó là không phải là rất đẹp, nhưng không phải đang nắm giữ nhiều giá trị trong một lĩnh vực.

+0

Cảm ơn bạn rất nhiều. Nó đã giúp tôi rất nhiều. – florins

+2

mã này không trả về Ta233148. Để nhận thay đổi đó CONNECT BY LEVEL <= LENGTH (REGEXP_REPLACE (str, '[^] +')) để CONNECT BY LEVEL <= LENGTH (REGEXP_REPLACE (str, '[^] +')) + 1 – sakthi

+0

Sử dụng mã này trực tiếp với bất cứ điều gì, nhưng một nhân vật splitter đơn giản sẽ trở lại cách để nhiều kết quả. Thay thế LENGTH (REGEXP_REPLACE (str, '[^] +')) + 1 bằng REGEXP_COUNT (str, '[^] +') và bạn sẽ nhận được kết quả mong đợi. – bkqc

1

Làm cách nào để thêm một hàm lặp lại và trả về tất cả các giá trị?

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; 

Sau đó, chỉ cần gọi hàm như một phần của truy vấn chọn.

+0

Về nguyên tắc tôi thích phương pháp này theo ý kiến ​​của tôi, nó có ứng dụng tổng quát hơn so với giải pháp được chấp nhận.Tuy nhiên tôi sẽ cải thiện nó bằng cách đi qua trong p_data, p_re, và cờ và tạo ra một loại một cái gì đó như "tạo hoặc thay thế loại mytype là bảng của varchar2 (4000)" và trả lại từ chức năng. Người ta có thể nhúng nó vào trong SQL như sau: chọn A.id, X.column_value từ someTable Một bảng nối chéo (regexp_substr_mr (A.textToSearch, 'regexp') X – Pancho

-1

Dưới đây là giải pháp dễ dàng cho câu hỏi của bạn.

SELECT REGEXP_SUBSTR('Txa233141b Ta233141 Ta233142 Ta233147 Ta233148', 
    '([a-zA-Z0-9]+\s?){1,}') "REGEXP_SUBSTR" 
    FROM DUAL; 
+0

Điều đó chỉ trả về chuỗi gốc, nó bao gồm cả Txa233141b mặc dù bắt đầu bằng ba ký tự không phải là số, không phải là hai ký tự như mô hình của OP yêu cầu. –

0

tôi sửa chữa @ Alex Poole answer hỗ trợ nguồn đa dòng và nhanh hơn thực hiện:

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 

dòng Nguồn:

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

Kết quả:

Txa233141b    
Ta233141     
Ta233142     
Ta233147     
Ta233148     
2      
22222222222222Ta233141 
2Ta233142    
2Ta233147    
3Txa233141b    
3Ta233141    
3Ta233142    
1

Thi s là một chút muộn, nhưng tôi cần thiết về cơ bản cùng một điều và không thể tìm thấy một đoạn trích tốt. Tôi cần tìm kiếm cột văn bản miễn phí của một bảng cho một số cụm từ và thu thập chúng. Vì điều này có thể hữu ích cho người khác, tôi đã bao gồm một phiên bản dựa trên câu hỏi này. Trong khi REGEXP_SUBSTR chỉ trả về một giá trị, Oracle cũng cung cấp một REGEXP_COUNT để cho bạn biết có bao nhiêu mục phù hợp trong một chuỗi đã cho, do đó bạn có thể tham gia với danh sách các chỉ mục để chọn như sau (tổng quát cho một dòng từ trên) 'source_table'):

WITH source_table 
    AS (SELECT 'Txa233141b Ta233141 Ta233142 Ta233147 Ta233148' as free_text 
      FROM dual) 
    , source 
    AS (SELECT cnt 
       , free_text 
      FROM (SELECT RegExp_Count(free_text, '(^|\s)[A-Za-z]{2}[0-9]{5,}(\s|$)') AS cnt 
         , free_text 
       FROM source_table) 
      WHERE cnt > 0) 
    , iota 
    AS (SELECT RowNum AS idx 
      FROM dual 
      CONNECT BY RowNum <= (SELECT Max(cnt) FROM source)) 
SELECT UNIQUE 
     RegExp_SubStr(s.free_text, '(^|\s)[A-Za-z]{2}[0-9]{5,}(\s|$)', 1, i.idx) AS result 
FROM source s 
    JOIN iota i 
    ON (i.idx <= s.cnt) 
Các vấn đề liên quan