2010-02-09 12 views
10

¿es posible ejecutar una pieza dinámica de sql dentro de plsql y devolver los resultados en un sys_refcursor? He pegado mi intento taaan lejos, pero la costura dosnt estar funcionando, este es el im error al obtener throught que mi uno aplicación de javaEjecutando una instrucción sql dinámica en un SYS_REFCURSOR

ORA-01006: variable de vinculación no existe ORA-06512: en "LIVEFIS. ERC_REPORT_PK", línea 116 ORA-06512: en la línea 1

pero que podría ser mal interpretado por somthing java, todo costuras a compilarse bien Soo im no seguro.

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; 

Im nuevo a plsql y aún más reciente para SQL dinámico Soo cualquier ayuda/sugerencia sería muy apreciada.

Gracias de nuevo

Jon

Respuesta

3

No se puede asignar un refcursor mediante el uso de ejecución inmediata.

Tendrá que construir el SQL en una cadena y luego usar abrir.

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

Técnicamente, si SELECT devuelve un tipo de datos de cursor, puede seleccionarlo en un cursor de ref (que ejecuta sql inmediato o estático). Pero tiene razón en que esta selección devuelve un valor de identificación, no un cursor de referencia. –

7

tendrá que enlazar los parámetros pAge y pPostcode. En SQL dinámico, los prefijaría con dos puntos (:). Si utiliza EXECUTE IMMEDIATE o OPEN ... FOR, que se unirá a sus parámetros a través de la posición, es por eso que les cambió el nombre: P1 y P2 en el ejemplo:

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; 

Nota: El número y posición de las variables se unen tiene que ser conocido en el momento de la compilación, esta es la razón por la que a menudo uso la construcción anterior (agregando el parámetro a su posición incluso si no se usa). Agregar una tautología (como en AND :P1 IS NULL) a una consulta no afectará su plan de explicación.

+1

+1: las variables CONTEXT son más complacientes en esta situación –

+0

@OMG Ponies: absolutamente –

+0

+1: Definitivamente. No sé lo que estaba pensando ... –

0

Utilice la sintaxis OPEN FOR y las variables de vinculación.

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 dinámico es difícil, difícil de entender y difícil de conseguir. Una de las áreas difíciles es manejar la repetición. Es una buena idea declarar repetidas secciones de bolierplate como constantes. Además, tenga en cuenta que podemos dividir cadenas grandes en varias líneas sin tener que concatenarlas con '||'. Esto reduce la sobrecarga de mantenimiento.

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; 
/
Cuestiones relacionadas