Ошибка Oracle: невозможно выполнить DML в запросе - PullRequest
1 голос
/ 05 сентября 2011

Почему я получаю следующую ошибку?

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;

Ответы [ 5 ]

7 голосов
/ 05 сентября 2011

Здесь есть две проблемы. Вы получаете ошибку «ORA-14551», потому что вы выполняете свою функцию в операторе SELECT, и, как ясно указывает сообщение об ошибке, мы не можем сделать это, когда функция выполняет DML. Решение этой проблемы состоит в том, чтобы выполнить это в PL / SQL или SQL * Plus.

Другая проблема состоит в том, что указатель ref является указателем на набор результатов, который может быть выбран только один раз. Ваша функция перебирает курсор ref и затем возвращает его. Это приведет к ошибке при попытке что-то сделать с возвращенным курсором ref, потому что он больше не действителен.

Да, и, кстати, любой код, который следует за оператором RETURN в функции, никогда не выполняется.

3 голосов
/ 05 сентября 2011

Вы можете избежать использования функции в операторе SELECT следующим образом:

var rc refcursor
exec :rc := func;
2 голосов
/ 13 ноября 2013

Вы можете назвать это

SET SERVEROUTPUT ON
EXEC DBMS_OUTPUT.PUT_LINE(your_fn_name(your_fn_arguments))
1 голос
/ 05 сентября 2011

Вы можете достичь того, что вы описали выше, выполнив простой запрос на обновление:

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

Есть ли причина, по которой вы действительно ДОЛЖНЫ иметь функцию?

0 голосов
/ 20 марта 2014

вы добавляете "PRAGMA AUTONOMOUS_TRANSACTION" для обновления

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

попробуйте

...