PL/SQL“ ORA-14551: 无法在查询中执行 DML 操作”解决

环境

 

        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行。

 

 


参考资料

 


        http://blog.csdn.net/gigiouter/article/details/7616627

 

 

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

 

        数据库事务是一种单元操作,要么是全部操作都成功,要么全部失败。在Oracle中,一个事务是从执行第一个数据管理语言(DML)语句开始,直到执行一个COMMIT语句,提交保存这个事务,或者执行一个ROLLBACK语句,放弃此次操作结束。事务的“要么全部完成,要么什么都没完成”的本性会使将错误信息记入数据库表中变得很困难,因为当事务失败重新运行时,用来编写日志条目的INSERT语句还未完成。针对这种困境,Oracle提供了一种便捷的方法,即自治事务。自治事务从当前事务开始,在其自身的语境中执行。它们能独立地被提交或重新运行,而不影响正在运行的事务。正因为这样,它们成了编写错误日志表格的理想形式。在事务中检测到错误时,您可以在错误日志表格中插入一行并提交它,然后在不丢失这次插入的情况下回滚主事务。因为自治事务是与主事务相分离的,所以它不能检测到被修改过的行的当前状态。这就好像在主事务提交之前,它们一直处于单独的会话里,对自治事务来说,它们是不可用的。然而,反过来情况就不同了:主事务能够检测到已经执行过的自治事务的结果。要创建一个自治事务,您必须在匿名块的最高层或者存储过程、函数、数据包或触发的定义部分中,使用PL/SQL中的PRAGMA AUTONOMOUS_TRANSACTION语句。在这样的模块或过程中执行的SQLServer语句都是自治的。触发无法包含COMMIT语句,除非有PRAGMA AUTONOMOUS_TRANSACTION标记。但是,只有触发中的语句才能被提交,主事务则不行。


我的邮箱[email protected]  新浪微博@Wentasy27

  微信公众平台:JustOracle(微信号:justoracle)

  数据库技术交流群:336882565(加群时验证 From CSDN XXX)

  Oracle交流讨论组https://groups.google.com/d/forum/justoracle

  By Larry Wen


katoon Sina CSDN
@Wentasy 博文仅供参考,欢迎大家来访。如有错误之处,希望批评指正。原创博文如需转载请注明出处,谢谢 :) [CSDN博客]

你可能感兴趣的:(pl/sql)