2010-11-04 15 views
6

Nie mogę przekonać się, dlaczego nie mogę dodać operacji DML wewnątrz Funkcja Oracle, szczególnie wewnątrz pętli kursora. Uważam, że Oracle nie obsługuje operacji DML w pętli kursora.Nie można wykonać operacji DML wewnątrz zapytania

Jak zrobić, jeśli muszę wstawić do tabeli wewnątrz pętli kursora? Utwórz nową procedurę składowania wewnątrz lub coś innego?

komunikat o błędzie: nie mogą wykonywać operacji DML wewnątrz zapytania

Oto moja funkcja,

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; 

Odpowiedz

11

Ty może użycie DML wewnątrz funkcji PL/SQL - nie ma problemu. Jednak funkcja może być wywołana tylko z PL/SQL, a nie z SQL - czyli można go nazwać tak:

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

... ale nie w ten sposób:

select test_func(empno) from emp; 

To prowadzi do opublikowany komunikat o błędzie.

Wiele osób (w tym ja) nie lubi funkcji, które mają takie "efekty uboczne", ale jest to kwestia najlepszej praktyki i standardów, a nie kwestii technicznej.

+0

Dzięki, to co pytam. – ppshein

11

Można wykonywać operacje DML wewnątrz funkcji Oracle PL/SQL i, , chociaż ogólnie nie jest to dobrą praktyką, wywołaj ją z SQL. Funkcja musi być oznaczona pragma AUTONOMOUS_TRANSACTION, a transakcja musi zostać zatwierdzona lub wycofana przed wyjściem z funkcji (patrz AUTONOMOUS_TRANSACTION Pragma).

Należy pamiętać, że tego rodzaju funkcja wywoływana z SQL może dramatycznie pogarszać wyniki zapytań. Zalecam używanie go wyłącznie do celów audytu tylko dla celów audytu.

Oto przykład skrypt począwszy od funkcji:

 
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; 

Uruchamiając poprzedni skrypt otrzymujemy następujący wynik:

 
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. Oprócz problemów z wydajnością i transakcjami bardzo trudno jest dokładnie określić, ile razy funkcja zostanie wykonana. Na przykład, ta instrukcja nie wywołuje w ogóle funkcji: wybierz * z dual tam, gdzie istnieje (wybierz test_func ('KING') z dual); SQL jest deklaratywny i nie ma sposobu, aby zagwarantować dokładnie, w jaki sposób zostanie wykonane zapytanie. –

Powiązane problemy