2012-05-15 2 views
0

결과 csv 문자열의 고유 값을 집계하여 csv 텍스트가있는 열에서 작동해야하는 간단한 집계 함수를 작성했습니다. 함수가 결과를 반환해야 할 때 ORA-06502 오류가 발생했을 때 함수가 끝까지 작동하는 것처럼 보입니다.오라클 plsql 집계 오류 : ORA-06502 : 문자열 버퍼가 너무 작습니다.

형 DEF : 여기

코드이다

create or replace type array_union_typ as object (

union_agg nvarchar2(1000), 

static function ODCIAggregateInitialize(sctx in out array_union_typ) 
       return number, 

member function ODCIAggregateIterate (self in out array_union_typ, 
             value in nvarchar2) 
       return number, 

member function ODCIAggregateTerminate (self   in array_union_typ, 
             return_value out nvarchar2, 
             flags  in number) 
       return number, 

member function ODCIAggregateMerge(self in out array_union_typ, 
            ctx2 in array_union_typ) 
       return number, 

static function agg_union(arg1 in nvarchar2, 
          arg2 in nvarchar2) 
       return nvarchar2 
); 

본체 :

SQL> desc uniontest 
Name          Null? Type 
----------------------------------------- -------- ---------------------------- 
I             NVARCHAR2(50) 

SQL> select * from uniontest; 

I 
-------------------------------------------------- 
a 
a 
b,c 
b,d,e 

최종적 여기

create or replace type body array_union_typ is 

static function ODCIAggregateInitialize(sctx in out array_union_typ 
            ) return number is 
begin 
    sctx := array_union_typ(null); 
    return ODCIConst.Success; 
end; 

member function ODCIAggregateIterate(self in out array_union_typ, 
            value in nvarchar2 
            ) return number is 
begin 
    union_agg := array_union_typ.agg_union(union_agg, value); 
    return ODCIConst.Success; 
end; 

member function ODCIAggregateTerminate(self in array_union_typ, 
             return_value out nvarchar2, 
             flags in number 
             ) return number is 
begin 
    dbms_output.put_line('result: '''|| union_agg || ''', length:' || length(union_agg)); --this still prints 
    return_value := self.union_agg; -- <-- this is where the error is indicated 
    --return_value := 'x'; -- returning this still gives the error. 
    return ODCIConst.Success; 
end; 

member function ODCIAggregateMerge(self in out array_union_typ, 
            ctx2 in array_union_typ 
            ) return number is 
begin 
    union_agg := array_union_typ.agg_union(union_agg, ctx2.union_agg); 
    return ODCIConst.Success; 
end; 

static function agg_union(arg1 in nvarchar2, 
          arg2 in nvarchar2) 
       return nvarchar2 is 
    result nvarchar2(1000); 
    orig nvarchar2(1000); 
begin 
    dbms_output.enable; 
    orig := replace(arg1||','||arg2, chr(0)); 

    FOR rec IN (SELECT DISTINCT(regexp_substr(orig, '[^,]+', 1, level)) AS a 
      FROM dual CONNECT BY regexp_substr(orig, '[^,]+', 1, level) IS NOT NULL ORDER BY a) LOOP 
     IF result IS NOT NULL THEN 
     result := result || ',' || rec.a; 
     ELSE 
     result := rec.a; 
     END IF; 
    END LOOP; 
    --dbms_output.put_line('endwith: ''' || result || ''''); 
    RETURN substr(result,1,1000); 
end; 
end; 

테스트 테이블 데이터 인 , 내가하려고하면이 일이 일어난다. 내가 단순히 잘못된 줄에 'X'와 같은 하나의 문자열을 전달하면 난 여전히 같은 오류가 발생,

SQL> select array_union(i) from uniontest; 
select array_union(i) from uniontest 
* 
ERROR at line 1: 
ORA-06502: PL/SQL: numeric or value error: character string buffer too small 
ORA-06512: at "M35456.ARRAY_UNION_TYP", line 25 


result: 'a,b,c,d,e', length:9 

: 집계 함수를 사용합니다. null 결과에서만 사라집니다. 나는 아이디어가 부족하다.

도움을 주셔서 감사합니다.

btw, 왜 누군가가 \ 0 문자를 추가했는지 알면, 나는 그것에 대해 알고 싶어 죽겠다. CONNECT BY 조건 행에 dependend되지 않기 때문에 내가 행의 무한이

SELECT DISTINCT(regexp_substr(orig, '[^,]+', 1, level)) AS a 
     FROM dual CONNECT BY regexp_substr(orig, '[^,]+', 1, level) IS NOT NULL ORDER BY a) 

결과를 틀리지 않는 경우

+0

이'nvarchar2'에 문제가 될 것으로 보인다

(... 여기 chr(0)하고 문제의 \0nvarchar2 관련이있는 것으로 보이지만, 다른 사람이 세부 사항에있는 칩해야합니다) 그것들이 단지'varchar2'로 변경되면 이것은 작동합니다. 내가하는 일보다는 내부적 인 것처럼 보이기 때문에 확실한 해결 방법을 볼 수 없습니다.대신 CLOB를 사용하여 무언가를 찢어 버릴 수도 있습니다. 또는 값을 다시 집계하고 구별 할 수있는 값을'listagg'에 전달하십시오. –

답변

0

ODCIaggregate 메서드는 nvarchar2으로 제대로 재생되지 않는 것 같습니다. 모두가 varchar2으로 변경되면 정상적으로 작동하므로 잘못된 작업을 수행 한 것으로 보이지 않습니다.

11gR2를 사용 중이므로 listagg 기능을 사용할 수 있지만 현재 고유 값을 알아야하기 때문에 현재이 기능을 사용하지 않는 경우 - 기존 regexp_substr 기능과 함께 사용할 수 있으므로 필요하지 않습니다. 당신의 자신의 종류/기능 :

SELECT REPLACE(LISTAGG(a, ',') WITHIN GROUP (ORDER BY a), chr(0), '') 
FROM (
    SELECT DISTINCT(regexp_substr(i, '[^,]+', 1, level)) AS a 
    FROM uniontest CONNECT BY regexp_substr(i, '[^,]+', 1, level) IS NOT NULL 
    ORDER BY a 
); 

... 제공하여 데이터 :

REPLACE(LISTAGG(A,',')WITHINGROUP(ORDERBYA),CHR(0),'') 
------------------------------------------------------ 
a,b,c,d,e 

이전 버전 대신 SELECT REPLACE(WM_CONCAT(a), chr(0), '')를 사용할 수 있습니다.

+0

'nvarchar2'에서'varchar2'로 변경해 주셔서 감사합니다. 또한'listagg'를 사용하면 코드가 좀 더 향상 될 것입니다. 나 외에는 아무도 그것을 볼 수 없다. 다행스럽게도 악센트 부호가있는 문자로 문자열에 사용할 필요가 없습니다. –

+0

@JoeDemarco -'listagg' 버전은 여전히'nvarchar2'로 정의 된 테이블 열과 호환되는 것으로 보입니다. 그래서 악센트 부호가있는 문자에 대처할 수있을 것이라고 생각했을 것입니다. –

+0

예, 집계가 작동 할 수도 있지만 여전히 문자열을 반환해야합니다.이 시점에서 문자열은 'varchar2'로 구두점을 찍어 모든 종류의 우둔함이 발생합니다. 일반적으로 빠른 탈모 결과. –

0

.

문자열에 결과 추가 문자를 더 빨리 반복하면 문자열이 커집니다.

+0

당신은 그때 그것을 실행 해 볼 수 있습니다. 사실 내가 원하는 것을 수행하고 그 결과가 그 함수에 의해 적절하게 반환된다면 그것을 볼 수 있습니다. 사실이 부분은 내가이 오류를 다루기 시작한 후에 더 일반적인 문자열 검색/루프 접근 방식에서 변경되었습니다. 또한 테스트 실행에서'ODCIAggregateTerminate'의'dbms_output.put_line'이 출력 결과를 표시하는 것을 볼 수 있습니다 :'result : 'a, b, c, d, e', length : 9' . –

관련 문제