【问题标题】:Oracle error: cannot perform DML in a queryOracle 错误:无法在查询中执行 DML
【发布时间】:2011-11-10 13:34:01
【问题描述】:

为什么会出现以下错误?

Error starting at line 1 in command:

select FUNC from dual
Error report:
SQL Error: ORA-14551: cannot perform a DML operation inside a query 
ORA-06512: at "ANONYMOUS.FUNC", line 15
14551. 00000 -  "cannot perform a DML operation inside a query "
*Cause:    DML operation like insert, update, delete or select-for-update
           cannot be performed inside a query or under a PDML slave.
*Action:   Ensure that the offending DML operation is not performed or
           use an autonomous transaction to perform the DML operation within
           the query or PDML slave.

功能:

create or replace function FUNC
return types.ref_cursor
AS
result_set types.ref_cursor;
alarm ofalarmmessages.ALARMID% TYPE;
username ofalarmmessages.USERNAME% TYPE;
alarmmsg ofalarmmessages.ALARMMESSAGE% TYPE;
dvice ofalarmmessages.DEVICEID% TYPE;
begin
OPEN result_set FOR
       SELECT USERNAME,ALARMID,ALARMMESSAGE,DEVICEID
    FROM   ofalarmmessages where newoldflag='N';
LOOP
    FETCH  result_set into username,alarm,alarmmsg,dvice;
        update ofalarmmessages set newoldflag ='Y' where alarmid= alarm;
END LOOP;
RETURN result_set;
CLOSE result_set;
END;
/
show errors;

【问题讨论】:

  • 是的,如果您尝试在 SELECT 语句中调用此函数,则会收到该错误。你有什么问题?
  • 如何从同一个函数中获取结果集以及更新操作。
  • 无论如何,这里的代码确实存在一些问题。 LOOP 将如何终止?你为什么要返回一个已经用尽的游标?你觉得 CLOSE 在 RETURN 之后会如何执行?
  • 或者请告诉我如何使用 var rc refcursor exec :rc := func;在我的程序中。
  • 请不要在函数内部进行更新操作,除非绝对必要,即你必须返回一些东西。否则它会很脏,并导致您遇到错误。使用程序更新;然后很清楚发生了什么。

标签: sql oracle stored-procedures plsql dml


【解决方案1】:

这里有两个问题。您收到“ORA-14551”错误是因为您正在 SELECT 语句中执行您的函数,并且正如错误消息清楚地表明的那样,当函数执行 DML 时我们不能这样做。这个问题的解决方法是在PL/SQL或SQL*Plus中执行。

另一个问题是引用游标是一个指向结果集的指针,它只能被获取一次。您的函数遍历 ref 光标,然后返回它。当您尝试对返回的 ref 游标执行某些操作时,这将导致错误,因为它不再有效。

哦,顺便说一句,函数中 RETURN 语句后面的任何代码都不会被执行。

【讨论】:

    【解决方案2】:

    您可以避免在这样的 SELECT 语句中使用该函数:

    var rc refcursor
    exec :rc := func;
    

    【讨论】:

    • 感谢您的回复。但我的问题是如何在上面的过程中提到的循环内进行更新操作。
    • 是吗?我以为你的问题是为什么会出现这个错误?
    • Dave 你能帮我得到所需的结果吗?
    • 我的回答是我建议你做的而不是 select func from dual.
    • 托尼,你能指导我解决上述问题并得到想要的结果吗?
    【解决方案3】:

    你可以这样称呼它

    SET SERVEROUTPUT ON
    EXEC DBMS_OUTPUT.PUT_LINE(your_fn_name(your_fn_arguments))
    

    【讨论】:

      【解决方案4】:

      您可以通过执行一个简单的更新查询来实现上述内容:

      update ofalarmmessages 
      set newoldflag='Y'
      where newoldflag='N';
      

      你真的必须有一个函数吗?

      【讨论】:

        【解决方案5】:

        您添加“PRAGMA AUTONOMOUS_TRANSACTION”进行更新

        create or replace function FUNC
        return types.ref_cursor
        PRAGMA AUTONOMOUS_TRANSACTION;
        /* ... */
        

        试试看

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-05-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-11-08
          相关资源
          最近更新 更多