【问题标题】:Solving "Cannot perform DML inside a query" error in Oracle解决 Oracle 中的“无法在查询中执行 DML”错误
【发布时间】:2012-04-01 16:51:36
【问题描述】:

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

运行它时
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;

【问题讨论】:

    标签: oracle plsql oracle10g


    【解决方案1】:

    一个函数应该计算并返回一个结果,而不是改变数据库的状态。如果您想在函数中执行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;
    

    【讨论】:

    • 感谢洞穴。我已经尝试过了,但是当我调用该程序时,它向我显示错误:调用“REG”时参数的数量或类型错误。我的程序是:CREATE OR REPLACE PROCEDURE reg(name in varchar2, cellNo in varchar2, voterId in varchar2, pass in varchar2, succ out NUMBER) AS BEGIN succ:=0;插入 logInfo 值(loginfo_seq.nextval,cellNo,pass,0);插入 passInfo 值(名称,cellNo,voterId);成功:= 1;结束;
    • @AwladLiton - 如果您使用OUT 参数创建过程,则需要传入第五个参数。编辑了我的答案以显示如何做到这一点。
    【解决方案2】:

    如果您只想记录信息,则使用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;
    

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

    【讨论】:

      猜你喜欢
      • 2011-11-10
      • 2019-11-05
      • 2012-02-02
      • 1970-01-01
      • 2011-05-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多