PL/SQL“ ORA-14551: 無法在查詢中執行 DML 操作”解決

來源:互聯網
上載者:User

環境

Oracle 11.2.0 + SQL Plus

問題

根據以下要求編寫函數:將scott.emp表中工資低於平均工資的職工工資加上200,並返回修改了工資的總人數。PL/SQL中有更新的操作,執行此函數報如下錯誤:ORA-16551: 無法在查詢中執行 DML 操作。

解決

在聲明函數時加上: PRAGMA AUTONOMOUS_TRANSACTION; 並在執行完DML後COMMIT。

動作記錄

--登入到Oracle
C:\Users\Wentasy>sqlplus wgb

SQL*Plus: Release 11.2.0.1.0 Production on 星期六 6月 29 15:32:21 2013

Copyright (c) 1982, 2010, Oracle.  All rights reserved.

輸入口令:

串連到:
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options

--編寫函數
SQL> CREATE OR REPLACE FUNCTION raise_sal
  2  RETURN NUMBER
  3  IS
  4  v_num NUMBER:=0;
  5  v_avg emp.sal%TYPE;
  6  BEGIN
  7    SELECT AVG(sal) INTO v_avg FROM emp;
  8    UPDATE emp SET sal=sal+200 WHERE sal < v_avg;
  9    v_num:=SQL%ROWCOUNT;
 10    RETURN v_num;
 11  END raise_sal;
 12  /

函數已建立。

--調用函數,出現錯誤
SQL> SELECT raise_sal() FROM DUAL;
SELECT raise_sal() FROM DUAL
      *
第 1 行出現錯誤:
ORA-14551: 無法在查詢中執行 DML 操作
ORA-06512: 在 "WGB.RAISE_SAL", line 8

--加上PRAGMA AUTONOMOUS_TRANSACTION和COMMIT。
SQL> CREATE OR REPLACE FUNCTION raise_sal
  2  RETURN NUMBER
  3  IS
  4  PRAGMA AUTONOMOUS_TRANSACTION;
  5  v_num NUMBER:=0;
  6  v_avg emp.sal%TYPE;
  7  BEGIN
  8    SELECT AVG(sal) INTO v_avg FROM emp;
  9    UPDATE emp SET sal=sal+200 WHERE sal < v_avg;
 10    v_num:=SQL%ROWCOUNT;
 11    COMMIT;
 12    RETURN v_num;
 13  END raise_sal;
 14  /

函數已建立。

--驗證第一步:查詢薪水平均值
SQL> SELECT AVG(sal) FROM emp;

  AVG(SAL)
----------
  2543.75

--驗證第二步:查詢薪水比平均薪水低的員工的總數
SQL> SELECT count(sal) FROM emp WHERE sal < (SELECT AVG(sal) FROM emp);

COUNT(SAL)
----------
        8

--驗證第三步:查詢資料
SQL> SELECT ename, sal FROM emp;

ENAME            SAL
---------- ----------
SMITH            1600
ALLEN            2400
WARD            2050
JONES            2975
MARTIN          2050
BLAKE            2850
CLARK            2450
KING            5000
TURNER          2300
JAMES            1750
FORD            3000

ENAME            SAL
---------- ----------
MILLER          2100

已選擇12行。

--驗證第四步:調用函數,如果為8,則實現功能
SQL> SELECT raise_sal() FROM dual;

RAISE_SAL()
-----------
          8

--驗證第五步:重新查詢表資料
SQL> SELECT ename, sal FROM emp;

ENAME            SAL
---------- ----------
SMITH            1800
ALLEN            2600
WARD            2250
JONES            2975
MARTIN          2250
BLAKE            2850
CLARK            2650
KING            5000
TURNER          2500
JAMES            1950
FORD            3000

ENAME            SAL
---------- ----------
MILLER          2300

已選擇12行。

參考資料

ORA-14551: 無法在查詢中執行 DML 操作

引用文字——更好的理解自治事務

資料庫事務是一種單元操作,要麼是全部操作都成功,要麼全部失敗。在Oracle中,一個事務是從執行第一個資料管理語言(DML)語句開始,直到執行一個COMMIT語句,提交儲存這個事務,或者執行一個ROLLBACK語句,放棄此次操作結束。事務的“要麼全部完成,要麼什麼都沒完成”的本性會使將錯誤資訊記入資料庫表中變得很困難,因為當事務失敗重新運行時,用來編寫日誌條目的INSERT語句還未完成。針對這種困境,Oracle提供了一種便捷的方法,即自治事務。自治事務從當前事務開始,在其自身的語境中執行。它們能獨立地被提交或重新運行,而不影響正在啟動並執行事務。正因為這樣,它們成了編寫錯誤記錄檔表格的理想形式。在事務中檢測到錯誤時,您可以在錯誤記錄檔表格中插入一行並提交它,然後在不丟失這次插入的情況下復原主事務。因為自治事務是與主事務相分離的,所以它不能檢測到被修改過的行的目前狀態。這就好像在主事務提交之前,它們一直處於單獨的會話裡,對自治事務來說,它們是停用。然而,反過來情況就不同了:主事務能夠檢測到已經執行過的自治事務的結果。要建立一個自治事務,您必須在匿名塊的最高層或者預存程序、函數、資料包或觸發的定義部分中,使用PL/SQL中的PRAGMA AUTONOMOUS_TRANSACTION語句。在這樣的模組或過程中執行的SQLServer語句都是自治的。觸發無法包含COMMIT語句,除非有PRAGMA AUTONOMOUS_TRANSACTION標記。但是,只有觸發中的語句才能被提交,主事務則不行。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.