开发者

cannot perform DML operation inside a query

I cannot convince why I can't add DML operation inside Oracle Function especially inside cursor loop. I feel Oracle don't support DML operation inside cursor loop.

How can I do If I need to insert into table inside cursor loop? Create new store procedure inside it or something else?

Error Message : cannot perform DML operation inside a query

Here is my function,

CREATE OR REPLACE FUNCTION TEST_FUNC(U_ID IN VARCHAR2)
RE开发者_如何学GoTURN 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;


You can use DML inside a PL/SQL function - no problem. However, the function can only be called from PL/SQL, not from SQL - i.e. it can be called like this:

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

... but not like this:

select test_func(empno) from emp;

That leads to the error message you posted.

Many people (including me) don't like functions that have "side effects" like this, but that is a matter of best practice and standards, not a technical issue.


You can perform DML operations inside an Oracle PL/SQL function and, although this is generally not a good practice, call it from SQL. The function has to be marked with a pragma AUTONOMOUS_TRANSACTION and the transaction has to be committed or rolled back before exiting the function (see AUTONOMOUS_TRANSACTION Pragma).

You should be aware that this kind of function called from SQL can dramatically degrade your queries performances. I recommend you use it only for audit purposes.

Here is an example script starting from your function:

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;

When running the previous script we get the following output:

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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜