2010-11-04 38 views
6

No puedo convencer por qué no puedo agregar operación DML dentro de Oracle Función especialmente dentro de cursor loop. Siento que Oracle no es compatible con la operación DML dentro del cursor loop.no se puede realizar la operación DML dentro de una consulta

¿Cómo puedo hacer si necesito insertar en la tabla dentro del bucle del cursor? ¿Crear un nuevo procedimiento de almacenamiento dentro de él o algo más?

mensaje de error: no puede realizar la operación DML dentro de una consulta

Aquí está mi función,

CREATE OR REPLACE FUNCTION TEST_FUNC(U_ID IN VARCHAR2) 
RETURN VARCHAR2 
IS 
    V_MESSAGE VARCHAR2(30); 
    CURSOR C_PERSON (V_ID VARCHAR2) IS 
     SELECT NAME_UPPER 
     FROM TBL_PERSON 
     WHERE NAME_UPPER = V_ID;     
BEGIN 
    FOR C_PERSON_CURSOR IN C_PERSON(U_ID) 
    LOOP 
     INSERT INTO TMP_PERSON(NAME) VALUES (C_PERSON_CURSOR.NAME_UPPER); 
    END LOOP; 

    RETURN V_MESSAGE; 

EXCEPTION 
WHEN OTHERS THEN 
    raise_application_error(-20001,'An error was encountered - '||SQLCODE||' -ERROR- '||SQLERRM); 
END; 

Respuesta

11

Usted puede uso LMD dentro de una función PL/SQL - no hay problema. Sin embargo, la función sólo puede ser llamado desde PL/SQL, no desde SQL - es decir, se le puede llamar así:

declare 
    l_message varchar2(30); 
begin 
    l_message := test_func('123'); 
end; 

... pero no de esta manera:

select test_func(empno) from emp; 

Esto nos lleva a el mensaje de error que publicaste

A muchas personas (incluyéndome a mí) no les gustan las funciones que tienen "efectos secundarios" como este, pero eso es una cuestión de mejores prácticas y estándares, no un problema técnico.

+0

Gracias, eso es lo que estoy pidiendo. – ppshein

11

Puede realizar operaciones DML dentro de una función Oracle PL/SQL y, aunque esto generalmente no es una buena práctica, llámelo desde SQL. La función debe estar marcada con un pragma AUTONOMOUS_TRANSACTION y la transacción debe confirmarse o retrotraerse antes de salir de la función (consulte AUTONOMOUS_TRANSACTION Pragma).

Debe tener en cuenta que este tipo de función llamada desde SQL puede degradar drásticamente sus actuaciones de consultas. Recomiendo que lo use solo para fines de auditoría.

Aquí es un script de ejemplo a partir de su función:

 
CREATE TABLE TBL_PERSON (NAME_UPPER VARCHAR2(30)); 
CREATE TABLE TMP_PERSON (NAME VARCHAR2(30)); 

INSERT INTO TBL_PERSON (NAME_UPPER) VALUES ('KING'); 

CREATE OR REPLACE FUNCTION TEST_FUNC(U_ID IN VARCHAR2) 
RETURN VARCHAR2 
IS 
    PRAGMA AUTONOMOUS_TRANSACTION; -- Needed to be called from SQL 

    V_MESSAGE VARCHAR2(2000); 
    CURSOR C_PERSON (V_ID VARCHAR2) IS 
     SELECT NAME_UPPER 
     FROM TBL_PERSON 
     WHERE NAME_UPPER = V_ID;     
BEGIN 
    FOR C_PERSON_CURSOR IN C_PERSON(U_ID) 
    LOOP 
     INSERT INTO TMP_PERSON(NAME) VALUES (C_PERSON_CURSOR.NAME_UPPER); 

     V_MESSAGE := SQL%ROWCOUNT 
      || ' Person record successfully inserted into TMP_PERSON table'; 
    END LOOP; 

    COMMIT; -- The current autonomous transaction need to be commited 
      -- before exiting the function. 

    RETURN V_MESSAGE; 

EXCEPTION 
WHEN OTHERS THEN 
    ROLLBACK; 
    raise_application_error(-20001,'An error was encountered - '||SQLCODE||' -ERROR- '||SQLERRM); 
END; 
/

PROMPT Call the TEST_FUNC function and insert a new record into TMP_PERSON table 
SELECT TEST_FUNC('KING') FROM DUAL; 

PROMPT Content of the TMP_PERSON table 
COL NAME FOR A30 
SELECT * FROM TMP_PERSON; 

Cuando se ejecuta la secuencia de comandos anterior obtenemos el siguiente resultado:

 
Table created. 

Table created. 

1 row created. 

Function created. 

Calling the TEST_FUNC function and insert a new record into TMP_PERSON table 

TEST_FUNC('KING') 
------------------------------------------------------------ 
1 Person record successfully inserted into TMP_PERSON table 

Content of the TMP_PERSON table 

NAME 
------------------------------ 
KING 
+2

+1. Además de los problemas de rendimiento y transacción, también es muy difícil saber exactamente cuántas veces se ejecutará la función. Por ejemplo, esta instrucción no llama a la función en absoluto: seleccione * desde dual donde existe (seleccione test_func ('KING') desde dual); SQL es declarativo y no hay forma de garantizar exactamente cómo se ejecutará una consulta. –

Cuestiones relacionadas