在Oracle中解决“无法在查询中执行DML”错误

时间:2012-04-01 16:51:36

标签: oracle plsql oracle10g

我已经创建了常规功能。它已成功创建。但是当我用

运行它时
select reg('awlad','01968688680','545466455','12345') from dual

它给了我这个错误:

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

我该如何解决这个问题?

CREATE OR REPLACE FUNCTION reg(
name in varchar2,
cellNo in varchar2,
voterId in varchar2,
pass in varchar2
)
RETURN NUMBER
IS 
succ NUMBER;
BEGIN 
      succ:=0;
      insert into logInfo values(loginfo_seq.nextval,cellNo,pass,0);
      succ:=1;
      insert into passInfo values(name,cellNo,voterId);
      succ:=2;
      RETURN succ;
END;

2 个答案:

答案 0 :(得分:6)

一个函数应该计算并返回一个结果,而不是改变数据库的状态。如果要在函数中执行DML(即,如果要在表中插入行),则无法在SELECT语句中调用该函数,因为SELECT语句无法更改状态的数据库。一般来说,最好将这种东西创建为存储过程而不是存储函数。

您可以像调用存储过程一样从PL / SQL块调用此函数

DECLARE
  l_success_code NUMBER;
BEGIN
  l_success_code := reg('awlad','01968688680','545466455','12345');
END;

如果要将其创建为过程

CREATE OR REPLACE PROCEDURE reg( name in varchar2, 
                                 cellNo in varchar2, 
                                 voterId in varchar2, 
                                 pass in varchar2, 
                                 succ out NUMBER ) 
AS 
BEGIN 
  succ:=0; 
  insert into logInfo values(loginfo_seq.nextval,cellNo,pass,0); 
  insert into passInfo values(name,cellNo,voterId); 
  succ:=1; 
END;

然后您需要通过传递OUT参数

来调用该过程
DECLARE
  l_success_code NUMBER;
BEGIN
  reg('awlad','01968688680','545466455','12345', l_success_code);
END;

答案 1 :(得分:3)

如果您只想做日志信息,那么使用autonomous transaction进行中间插入是合适的。

CREATE OR REPLACE FUNCTION reg(NAME IN VARCHAR2, 
                               cellNo IN VARCHAR2, 
                               voterId IN VARCHAR2, 
                               pass IN VARCHAR2)
   RETURN NUMBER IS
   --
   PROCEDURE do_loginfo (p_id NUMBER, 
                         p_cellNo VARCHAR2, 
                         p_pass VARCHAR2, 
                         p_x NUMBER) IS
   PRAGMA AUTONOMOUS_TRANSACTION
   BEGIN
      INSERT INTO logInfo VALUES (p_id, p_cellNo, p_pass, p_x);
      COMMIT;
   END do_loginfo;
   PROCEDURE do_passInfo (p_name VARCHAR2, 
                          p_cellNo VARCHAR2, 
                          p_voterId VARCHAR2) IS
   PRAGMA AUTONOMOUS_TRANSACTION
   BEGIN
      INSERT INTO passInfo VALUES (p_name, p_cellNo, p_voterId);
      COMMIT;
   END do_passInfo;
   --
   succ NUMBER;
BEGIN
   succ := 0;
   do_logInfo (loginfo_seq.NEXTVAL, cellNo, pass, 0);
   succ := 1;
   do_passInfo (NAME, cellNo, voterId);
   succ := 2;
   RETURN succ;
END;

请注意,它对于调试目的很有用,但由于它不是事务性的,因此不应该用它来记录数据(因为即使主事务被回滚,插入的行也会保留。)