2010-07-19 409 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?

僅供參考我沒有粘貼循環內的整個代碼。基本上在循環內部,我在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


爲了完整起見,可以在SELECT語句中調用的函數中包含DML和DDL語句。解決方法是使用AUTONOMOUS_TRANSACTION編譯指示。這很少是一個好主意,在這種情況下肯定無濟於事。由於交易是獨立的,它所做的更改對於主叫交易是不可見的。在這種情況下意味着函數無法看到刪除或插入GTT中的結果。

+0

查看代碼以及它使用GTT的方式,看起來您可以在單個操作中插入/選擇結果,以確定填充'record_type'。 我還會調用'record_type'類似'role_record' - 更好地保留類型的_type。 – JulesLt 2010-07-19 13:06:10

0

該錯誤表示您正在從修改數據的函數(在您的情況下爲DELETE,INSERT)中進行選擇。

如果您需要該功能,請將該功能中的數據修改語句移除到單獨的SP中。 (我想我不明白從代碼片斷你爲什麼要刪除並插入循環內)