ORA-14551:无法在查询中执行DML操作

时间:2010-07-19 11:27:33

标签: oracle plsql temp-tables

我在package内有以下内容,它给了我一个错误:

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错误?

仅供参考我没有在循环中粘贴整个代码。基本上在循环内部我在GTT中输入内容,从GTT中删除内容然后从GTT中选择内容并将其附加到光标。

2 个答案:

答案 0 :(得分: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


为了完整起见,可以在SELECT语句中调用的函数中包含DML和DDL语句。解决方法是使用AUTONOMOUS_TRANSACTION编译指示。这很少是一个好主意,在这种情况下肯定无济于事。因为事务是自治的,所以它所做的更改对于调用事务是不可见的。在这种情况下意味着该功能无法在GTT中看到删除或插入的结果。

答案 1 :(得分:0)

错误意味着您正在从修改数据的函数中进行选择(在您的情况下为DELETE,INSERT)。

如果您需要该功能,请将该函数中的数据修改语句删除到单独的SP中。 (我想我不明白你在代码片段中为什么要删除并在循环中插入)