2010-07-19 1 views
3

У меня есть следующие внутри package и он дает мне ошибку:ORA-14551: не может выполнить операцию DML внутри запроса

ORA-14551: cannot perform a DML operation inside a query 

Кодекс:

DECLARE 
    CURSOR F IS 
     SELECT ROLE_ID 
     FROM ROLE 
     WHERE GROUP = 3 
     ORDER BY GROUP ASC; 

BEGIN 
FOR R IN F LOOP 

DELETE FROM my_gtt_1; 
COMMIT; 

INSERT INTO my_gtt_1 
    (USER, role, code, status) 
(SELECT 
trim(r.user), r.role, r.code, MAX(status_id) 
FROM 
    table1 r, 
    tabl2 c 
WHERE 
     r.role = R.role 
    AND r.code IS NOT NULL 
    AND c.group = 3 
    GROUP BY 
    r.user, r.role, r.code); 

    SELECT c.role, 
        c.subgroup, 
        c.subgroup_desc, 
        v_meb_cnt 
        INTO record_type 
      FROM ROLE c 
      WHERE c.group = '3' and R.role = '19' 
      GROUP BY c.role,c.subgroup,c.subgroup_desc; 

    PIPE ROW (record_type); 



END LOOP; 

END; 

я называю пакет, как это в одном из моих процедур ...:

OPEN cv_1 for SELECT * FROM TABLE(my_package.my_func); 

, как я могу избежать этого ORA-14551 эр ROR?

FYI Я не вставлял весь код внутри цикла. В основном внутри цикла я вхожу в материал GTT, удаляя материал из GTT, а затем выбираю материал из GTT и добавляю его к курсору.

ответ

10

Смысл ошибки совершенно ясен: если мы вызываем функцию из оператора SELECT, она не может выполнять инструкции DML , то есть INSERT, UPDATE или DELETE, или действительно заявления DDL приходят к этому.

Теперь фрагмент кода, который вы опубликовали, содержит вызов PIPE ROW, поэтому вы явно называете это SELECT * FROM TABLE(). Но он включает в себя заявления DELETE и INSERT, так что это явно не соответствует уровням чистоты, необходимым для функций в операторах SELECT.

Итак, вам нужно удалить эти инструкции DML. Вы используете их для заполнения глобальной временной таблицы, но это хорошая новость. У вас нет никакого кода, который фактически использует GTT, поэтому это трудно быть уверенным, но использование GTT часто не нужно. С более подробной информацией мы можем предложить обходные пути.

Это связано с this other question of yours? Если да, то вы следовали моему совету, чтобы проверить that answer I had given to a similar question?


Для полноты картины можно включать операторы DML и DDL в функции, вызываемой в ЗЕЬЕСТЕ. Обходной путь заключается в использовании прагмы AUTONOMOUS_TRANSACTION. Это редко бывает хорошей идеей и, конечно же, не поможет в этом сценарии. Поскольку транзакция является автономной, изменения, которые она делает, невидимы для вызывающей транзакции. В этом случае означает, что функция не может видеть результат удаления или вставки в GTT.

+0

Рассматривая код и способ использования GTT, похоже, что вы можете определенно заполнить 'record_type' результатом вставки/выбора за одну операцию. Я бы назвал «record_type» что-то вроде «role_record» - лучше сохранить _type для типов. – JulesLt

0

Ошибка означает, что вы выбрали функцию, которая изменяет данные (DELETE, INSERT в вашем случае).

Удалите инструкции модификации данных из этой функции в отдельный SP, если вам нужна эта функциональность. (Я думаю, я не понимаю из фрагмента кода, почему вы хотите удалить и вставить внутри цикла)