2014-03-05 3 views
0

내 절차 나는 긴 문자열 p_LstKH을 분할 한 후 커서 c_dsKH에 넣고 싶습니다오라클 - 사용이 CLOB 매개 변수

CREATE OR REPLACE PROCEDURE my_procedure(res OUT SYS_REFCURSOR , p_LstKH CLOB) 
AS 
CURSOR c_dsKH 
    IS 
    SELECT TO_NUMBER(REGEXP_SUBSTR(p_LstKH,'[^,]+', 1, level)) value FROM dual 
    CONNECT BY REGEXP_SUBSTR(p_LstKH, '[^,]+', 1, level) IS NOT NULL; 
BEGIN 
... 
END; 

와 문에 의해 연결합니다. 예 : p_LstKH = '1, 2, ..., 10000'내가 그 절차를 실행할 때

c_dsKH.value 
1 
2 
... 
10000 

그러나, 나는 "조작에 의한 연결을위한 메모리가 부족합니다"오류가 발생합니다. p_LstKH CLOB 매개 변수를 p_LstKH VARCHAR2로 바꾸려고 시도한 다음 다른 오류 "ORA-06502 : PL/SQL : 숫자 또는 값 오류 : 문자열 버퍼가 너무 작음"이 표시됩니다.

지금 어떻게해야합니까? 간단히 말해서 긴 문자열을 분리하고 싶습니다. 감사합니다.

+0

정규 표현식은 최대 512 바이트 [여기 확인]을 포함 할 수 있습니다 (http://docs.oracle.com/cd/B19306_01/server.102/b14200/functions131.htm) . 전역 임시 테이블을 작성하고 결과를 저장하는 프로 시저를 작성할 수 있습니다. 및 GT 테이블에서 쿼리. –

+1

@simplify_life - * 패턴 *은 최대 512 바이트까지 가능합니다. 여기에있는 패턴은''[^,] + ''로, 이것은 단지 5입니다. 이것은 문제가되는 큰 입력 문자열에 대해 생성되는 레벨 수입니다. –

+0

@ Alex..Correct .. 내 잘못 –

답변

2

당신은 쉼표를 기반으로 자신의 분할을 수행하고 값을 반환하는 파이프 라인 기능을 사용할 수

select * from table(split_clob('X,Y,Z')); 

COLUMN_VALUE 
------------ 
X    
Y    
Z    

당신이 만약 : 그럼 당신은 테이블로 그 처리 할 수 ​​있습니다

create or replace function split_clob(p_lstkh clob) 
return sys.odcivarchar2list pipelined 
as 
    start_pos pls_integer := 0; 
    end_pos pls_integer := 0; 
    clob_length pls_integer; 
    str varchar2(4000); 
begin 
    clob_length := dbms_lob.getlength(p_lstkh); 
    while end_pos <= clob_length loop 
    start_pos := end_pos + 1; 
    end_pos := dbms_lob.instr(p_lstkh, ',', start_pos, 1); 
    if end_pos <= 0 then 
     end_pos := clob_length + 1; 
    end if; 
    str := dbms_lob.substr(p_lstkh, end_pos - start_pos, start_pos); 
    pipe row (str); 
    end loop; 
end; 
/

을 여전히 필요로하는 참조 커서는 프로 시저가 커서 대신 커서 대신 연결선을 사용할 수 있습니다. 데모로

는 더 이상 32K의 실제 (꾸며낸) CLOB 작업 표시합니다 :

declare 
    clob_val clob := 'A,B,C,D,E,F,G,H,I'; 
begin 
    for i in 1..2000 loop 
    dbms_lob.append(clob_val, ',A,B,C,D,E,F,G,H,I'); 
    end loop; 
    dbms_output.put_line('Clob size: ' || dbms_lob.getlength(clob_val)); 
    for r in (select * from table(split_clob(clob_val)) where rownum < 6) loop 
    dbms_output.put_line(r.column_value); 
    end loop; 
end; 
/

anonymous block completed 
Clob size: 36017 
A 
B 
C 
D 
E 
+1

고맙습니다. 당신은 내 영웅 알렉스 풀입니다 :) –

1

이 작동해야하지만 refcursor을 반환하는 함수를 필요로한다. 당신이 그것으로 작업 할 수있는 경우 :

create or replace 
function splitter(pc CLOB) return sys_refcursor 
as 
    lc sys_refcursor; 
begin 
    open lc for 
    with s(tot, sub, offset) as (
     select pc||',' tot, 
     dbms_lob.substr(pc, dbms_lob.instr(pc, ',', 1)-1, 1) sub, 
     dbms_lob.instr(pc, ',', 1)+1 offset 
     from dual 
     union all 
     select tot, 
     dbms_lob.substr(tot, dbms_lob.instr(tot, ',', offset+1)-offset, offset), 
     dbms_lob.instr(tot, ',', offset+1)+1 
     from s 
     where offset < dbms_lob.getlength(tot) 
    ) 
    select sub 
    from s; 

    return lc; 
end; 
/

var c refcursor; 
exec :c := splitter('a,b,c,d,e,f'); 
print c; 
관련 문제