2010-02-09 3 views
10

에 동적 SQL 문을 실행하면 plsql에서 동적 SQL을 실행하고 결과를 sys_refcursor로 반환 할 수 있습니까? 나는 한혜진까지 내 시도를 붙여 넣은하지만 dosnt 솔기가 작동하는이 내 자바 응용 프로그램SYS_REFCURSOR

throught를 받고 오류 메신저입니다 ORA-01006 : 바인드 변수가 ORA-06512 존재하지 않습니다 "LIVEFIS에서. ERC_REPORT_PK ", 라인 (116) ORA-06512 : 줄 1

하지만 자바 잘못 해석 뭔가를해야만 될 수에서, 모든 솔기는 김 미세 컴파일 확실하지 메신저합니다.

procedure all_carers_param_dy (pPostcode in carer.postcode%type, pAge Number 
           ,pReport out SYS_REFCURSOR) is 
    begin 
    declare 
     lsql varchar2(500) :='SELECT c.id FROM carer c, cared_for cf,carer_cared_for ccf ' 
      ||' where c.id = ccf.carer_id (+)' 
      ||' AND cf.id (+) = ccf.cared_for_id'; 

    begin 

    if pPostcode is not null and pAge <= 0 then 
     lsql := lsql||' AND c.postcode like ''%''|| upper(pPostcode)||''%'''; 
     elsif pPostcode is null and pAge > 0 then 
     lsql := lsql||' AND ROUND((MONTHS_BETWEEN(sysdate,c.date_of_birth)/12)) = pAge'; 
     elsif pPostcode is not null and pAge > 0 then 
     lsql := lsql ||' AND ROUND((MONTHS_BETWEEN(sysdate,c.date_of_birth)/12)) = pAge' 
         ||' AND c.postcode like ''%''|| upper(pPostcode)||''%'''; 
     end if; 


     execute immediate lsql 
     into pReport; 


    end; 
    end; 

Impls에 대한 새로운 기능이나 동적 SQL에 대한 새로운 기능은 모든 도움/제안 사항이 크게 줄어 들었습니다.

덕분에 다시

답변

3

당신은 즉시 실행의 사용을 통해 refcursor를 할당 할 수 없습니다.

SQL을 문자열로 작성한 다음 open을 사용해야합니다.

sql_str := 'SELECT * FROM...'; 
open pReport for sql_str; 
+0

기술적으로 SELECT가 커서 데이터 유형을 반환하는 경우 참조 커서 (직접 또는 정적 SQL을 실행)로 선택할 수 있습니다. 그러나이 선택이 id 커서가 아닌 id 값을 반환한다는 점에서 옳습니다. –

7

당신은 매개 변수 pAgepPostcode을 결합해야합니다. 동적 SQL에서는 콜론 (:)을 접두어로 붙입니다. P1과 : 예에서 P2 :

DECLARE 
    lsql VARCHAR2(500) := 'SELECT c.id 
          FROM carer c, cared_for cf, carer_cared_for ccf 
          WHERE c.id = ccf.carer_id (+) 
          AND cf.id (+) = ccf.cared_for_id'; 
BEGIN 
    IF pPostcode IS NULL THEN 
     lsql := lsql || ' AND :P1 IS NULL'; 
    ELSE 
     lsql := lsql || ' AND c.postcode like ''%''|| upper(:P1)||''%'''; 
    IF pPostcode pAge > 0 THEN 
     lsql := lsql || ' AND :P2 = ROUND((MONTHS_BETWEEN(sysdate, 
                 c.date_of_birth)/12))'; 
    ELSE 
     lsql := lsql || ' AND nvl(:P2, -1) <= 0'; 
    END IF; 
    OPEN pReport FOR lsql USING pPostcode, pAge; 
END; 

참고 : 바인드 변수의 수와 위치가 가 될 당신이 EXECUTE IMMEDIATE 또는 OPEN ... FOR를 사용하는 경우, 당신은 내가 그들을 개명 이유는, 위치를 통해 매개 변수를 바인딩 컴파일 시간이 인 것으로 알려져 있으므로, 위의 구문을 사용하여 (매개 변수를 사용하지 않더라도 매개 변수를 추가하는 경우가 많습니다.) terology (AND :P1 IS NULL에서와 같이)를 쿼리에 추가해도 Explain 플랜에 영향을 미치지 않습니다.

+1

+1 : CONTEXT 변수가이 상황에서 더 수용됩니다 –

+0

@OMG Pony : 절대적으로 –

+0

+1 : 확실히. 내가 뭘 생각하는지 모르겠다. –

0

OPEN FOR 구문과 바인드 변수를 사용하십시오.

procedure all_carers_param_dy (pPostcode in carer.postcode%type, pAge Number 
          ,pReport out SYS_REFCURSOR) 
is 
    lsql varchar2(500) :='SELECT c.id FROM carer c, cared_for cf,carer_cared_for ccf ' 
     ||' where c.id = ccf.carer_id (+)' 
     ||' AND cf.id (+) = ccf.cared_for_id'; 

begin 

if pPostcode is not null and pAge <= 0 then 
    lsql := lsql||' AND c.postcode like upper(''%''||:1||''%'')'; 
    open pReport for lsql using pPostcode; 
    elsif pPostcode is null and pAge > 0 then 
    lsql := lsql||' AND ROUND((MONTHS_BETWEEN(sysdate,c.date_of_birth)/12)) = :1'; 
    open pReport for lsql using pAge; 
    elsif pPostcode is not null and pAge > 0 then 
    lsql := lsql ||' AND ROUND((MONTHS_BETWEEN(sysdate,c.date_of_birth)/12)) = :1' 
        ||' AND c.postcode like upper(''%''||:2||''%'')'; 
    open pReport for lsql using pAge, pPostcode; 
    end if; 

end all_carers_param_dy; 
/

동적 SQL은 어렵고 이해하기 어렵고 올바르게하기가 어렵습니다. 까다로운 영역 중 하나는 반복을 처리하는 것입니다. bolierplate의 반복 섹션을 상수로 선언하는 것이 좋습니다. 또한 '||'으로 연결하지 않고도 여러 줄로 큰 문자열을 분할 할 수 있습니다. 이렇게하면 유지 관리 오버 헤드가 줄어 듭니다.

create or replace procedure all_carers_param_dy 
    (pPostcode in carer.postcode%type 
     , pAge Number 
     , pReport out SYS_REFCURSOR) 
is 
    lsql varchar2(500) ; 

    root_string constant varchar2(500) :='SELECT c.id FROM carer c 
           , cared_for cf,carer_cared_for ccf 
         where c.id = ccf.carer_id (+) 
         and cf.id (+) = ccf.cared_for_id'; 
    pc_string constant varchar2(256) := 
     ' AND c.postcode like upper(''%''||:pc||''%'')'; 
    age_string constant varchar2(256) := 
     ' AND ROUND((MONTHS_BETWEEN(sysdate,c.date_of_birth)/12)) = :age'; 
begin 

if pPostcode is not null and pAge <= 0 then 
    lsql := root_string || pc_string; 
    open pReport for lsql using pPostcode; 

    elsif pPostcode is null and pAge > 0 then 
    lsql := root_string || age_string; 
    open pReport for lsql using pAge; 

    elsif pPostcode is not null and pAge > 0 then 
    lsql := root_string || age_string 
         || pc_string; 
    open pReport for lsql using pAge, pPostcode; 

    end if; 
end all_carers_param_dy; 
/