Oracle 在存储过程或函数中执行字符串sql ORA-14551: 无法在查询中执行 DML 操作execute immediate的简单用法,oracleORACLE EXECUTE IMMEDIATE 小结

有时,我们需要在存储过程或函数中根据条件拼凑一些sql字符串语句,然后再执行拼凑后的sql字符串,如何做到呢?

参考以下代码:

FUNCTION CALCULATE_TARGET_SCORE (CUR_MONTH IN NVARCHAR2)
   RETURN NCLOB
IS
   PRAGMA AUTONOMOUS_TRANSACTION;

   TVALUE_SQL          VARCHAR2 (2000);         --查询目标值的sql(不能把类型声明为NVARCHAR2)
   RESULT_STR          NCLOB;
   KPI_VALUE           NVARCHAR2 (200);
   CUR_MONTH_BILL_ID   NUMBER (19);                                    --固话单ID
BEGIN
   --获得当前固话单
   SELECT MAX (ID)
     INTO CUR_MONTH_BILL_ID
     FROM GP_MONTH_BILL
    WHERE MONTH = CUR_MONTH AND IS_USE = 1;


   --循环获得每个明细的完成值sql
   IF CUR_MONTH_BILL_ID > 0                                             --区县指标
   THEN
      TVALUE_SQL :=
            'SELECT TO_CHAR('
         || CUR_ROW.MAIN_FIELD
         || ') FROM '
         || CUR_ROW.END_TABLE
         || '_'
         || CUR_MONTH
         || ' WHERE TO_CHAR(DISTRICT_ID)='''
         || CUR_ROW.E_DISTRICT_ID
         || '''';
   ELSE                                                               --客户经理指标
      TVALUE_SQL :=
            'SELECT TO_CHAR('
         || CUR_ROW.MAIN_FIELD
         || ') FROM '
         || CUR_ROW.END_TABLE
         || '_'
         || CUR_MONTH
         || ' WHERE MANAGER_NO='''
         || CUR_ROW.MANAGER_NO
         || '''';
   END IF;

   BEGIN
      EXECUTE IMMEDIATE TVALUE_SQL INTO KPI_VALUE;      --执行sql,得到完成值kpi_value
   EXCEPTION
      WHEN OTHERS
      THEN
         RESULT_STR :=
               RESULT_STR
            || '<br/> sql执行错误:'
            || TVALUE_SQL
            || ' INTO KPI_VALUE';
   END;
--一些sql逻辑,含dml语句
COMMIT; END;

关键语句:EXECUTE IMMEDIATE TVALUE_SQL INTO KPI_VALUE;

本项目涉及到的知识点:

1)在该示例中,需要把查询的值动态赋值给一个变量。注意变量的赋值不是在sql字符串中去拼凑,而是在执行sql字符串时在末尾加入 INTO VAL

2)如果要通过查询方式调用函数,同时函数中包含DML 语句时,在声明函数需要加入 PRAGMA AUTONOMOUS_TRANSACTION;

查询调用函数示例: SELECT YOUR_FUN(VAL1,VAL2...) FROM DUAL;

3)如果函数声明中含有 PRAGMA AUTONOMOUS_TRANSACTION; 则在函数结尾加入commit 或 rollback

关联阅读:ORA-14551: 无法在查询中执行 DML 操作


关于EXECUTE IMMEDIATE的扩展阅读:

execute immediate的简单用法(oracle)

ORACLE EXECUTE IMMEDIATE 小结

把一个查询结果集插入到临时表,需要用变量写法,参考如下:

declare
   l_sal    pls_integer := 2000;
begin
   execute immediate 'insert into temp(empno, ename) ' ||
                    '           select empno, ename from emp ' ||
                    '           where   sal > :1'
     using l_sal;
   commit;
end;