【问题标题】:how to catch the error of execute immediate (open for)?如何捕捉执行立即(开放)的错误?
【发布时间】:2019-12-13 03:13:33
【问题描述】:

我有这个程序:

PROCEDURE proc_with_cursor(  P_PARAM1_IN NUMBER, P_PARAM2_IN NUMBER, P_CURSOR_OUT OUT SYS_REFCURSOR)
    IS
    v_sql   VARCHAR2 (32767);
    v_script   VARCHAR2 (32767);
    v_bind_vars VARCHAR2 (32767);
BEGIN
     v_sql := 'BEGIN OPEN :1 FOR :2 ';
     v_bind_vars := P_PARAM1_IN||', '||P_PARAM2_IN;
     v_sql := v_sql||' USING '||v_bind_vars||'; ';
    --tried also following  but also couldn't catch the error!
    --v_sql := v_sql ||'EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE(''error: ''||SQLCODE||'' - ''||SQLERRM); END;';
    v_sql := v_sql||' END;';

    v_script := 'select sysdate from dual where 1= :bind_first and 2 = :bindsecond';

    EXECUTE IMMEDIATE v_sql using P_CURSOR_OUT, v_script;     

    EXCEPTION 
    WHEN OTHERS THEN 
        DBMS_OUTPUT.PUT_LINE('error: '||SQLCODE||' - '||SQLERRM); -- this part is not catching the error!!!!!   
END;

有时,脚本会抛出如下错误:

ORA-12847:由于并发 DDL 操作重试解析

[错误] 执行 (1:1): ORA-12847: 由于并发 DDL 操作重试解析

我的问题是:如何捕获该错误?

【问题讨论】:

  • 为什么要使用execute immediate 打开游标?能否请您提供更真实的代码。
  • 为了将字符串传递给使用过程中动态创建的绑定变量
  • 使用 v_bind_vars 为 v_script 打开 P_CURSOR_OUT;会抱怨并非所有变量都绑定
  • 如果在编译时不知道变量的数量,那么使用DBMS_SQL
  • 有没有办法将结果从 dbms_sql 游标传递到输出 refcursor 参数?

标签: oracle plsql cursor procedure


【解决方案1】:

我不明白你的问题。如果你有这个程序

CREATE OR REPLACE PROCEDURE proc_with_cursor(  p_param1_in NUMBER, p_param2_in NUMBER, p_cursor_out OUT SYS_REFCURSOR)
IS
    v_script   VARCHAR2 (32767);
BEGIN
    v_script := 'select sysdate fromM dual where 1= :bind_first and 2 = :bindsecond';
    OPEN p_cursor_out FOR v_script USING p_param1_in, p_param2_in;
END;

然后你得到这个:

DECLARE
    cur SYS_REFCURSOR;
BEGIN
    proc_with_cursor(1, 2, cur);    
end;
/

Error at line 1
ORA-00923: FROM keyword not found where expected
ORA-06512: at "xxx.PROC_WITH_CURSOR", line 6
ORA-06512: at line 4

您还想得到什么?您的(糟糕的)代码正在运行:

CREATE OR REPLACE PROCEDURE proc_with_cursor(  P_PARAM1_IN NUMBER, P_PARAM2_IN NUMBER, P_CURSOR_OUT OUT SYS_REFCURSOR) IS
    v_sql   VARCHAR2 (32767);
    v_script   VARCHAR2 (32767);
    v_bind_vars VARCHAR2 (32767);
BEGIN
    v_sql := 'BEGIN OPEN :1 FOR :2 ';
    v_bind_vars := P_PARAM1_IN||', '||P_PARAM2_IN;
    v_sql := v_sql||' USING '||v_bind_vars||'; ';
    v_sql := v_sql||' END;';

    v_script := 'select sysdate fromm dual where 1= :bind_first and 2 = :bindsecond';

    EXECUTE IMMEDIATE v_sql USING P_CURSOR_OUT, v_script;     

EXCEPTION 
    WHEN OTHERS THEN 
        DBMS_OUTPUT.PUT_LINE('error: '||SQLCODE||' - '||SQLERRM);   
END;


DECLARE
    cur SYS_REFCURSOR;
BEGIN
    proc_with_cursor(1,2, cur);
END;

在 DBMS_OUTPUT 上打印 error: -923 - ORA-00923: FROM keyword not found where expected

如果你想获得例外,那么做

CREATE OR REPLACE PROCEDURE proc_with_cursor(  P_PARAM1_IN NUMBER, P_PARAM2_IN NUMBER, P_CURSOR_OUT OUT SYS_REFCURSOR) IS
    v_sql   VARCHAR2 (32767);
    v_script   VARCHAR2 (32767);
    v_bind_vars VARCHAR2 (32767);
BEGIN
    ...    
    EXECUTE IMMEDIATE v_sql USING P_CURSOR_OUT, v_script;     

EXCEPTION 
    WHEN OTHERS THEN 
        DBMS_OUTPUT.PUT_LINE('error: '||SQLCODE||' - '||SQLERRM);  
        RAISE;  
END;

【讨论】:

  • 您正在将参数一一绑定到光标,而我需要将其作为逗号分隔的字符串进行。这意味着 open for 应该在 execute immediate 中执行,有时会返回主题中描述的错误(错误不是由过程产生的,而是由 execute immediate 功能本身产生的)
  • 您不能将参数绑定为逗号分隔的字符串(整个字符串将被视为 one 值)。要么绑定一个集合,例如TABLE OF NUMBER 或使用 DBMS_SQL 包。
  • 在 cmets 中讨论过!是的,如果使用 begin-end 块立即执行,您可以!
  • 但这是错误的做法。例如,如果您传递包含单引号 ' 的 DATE 值或文本,那么您会遇到问题。避免此类问题是绑定变量的主要目的之一。
【解决方案2】:

您不能将对象 names(例如游标名称)和变量 names 绑定到动态 SQL,只能绑定 values。我认为这可能会达到您的预期:

PROCEDURE proc_with_cursor(  p_param1_in NUMBER, p_param2_in NUMBER, p_cursor_out OUT SYS_REFCURSOR)
IS
    v_script   VARCHAR2 (32767);
BEGIN
    v_script := 'select sysdate from dual where 1= :bind_first and 2 = :bindsecond';

    OPEN p_cursor_out FOR v_script USING p_param1_in, p_param2_in;

EXCEPTION
    WHEN OTHERS THEN
        dbms_output.put_line('error: '||sqlcode||' - '||sqlerrm); 
END;

【讨论】:

  • 这不是关于对象的名称,而是关于! v_bind_vars := P_PARAM1_IN||', '||P_PARAM2_IN;将收集值,然后将它们传递给 USING,例如,当您将拥有一组值,这些值应该从带有大量绑定变量的 clob 传递给脚本时
  • 好的,我可能在这方面误读了你。但是您正在编写“BEGIN OPEN :1 FOR :2”,这将不起作用,因为您无法为 (1) 游标变量名称和 (2) 查询绑定值。您只能绑定查询使用(如数字、varchar2s、日期)。
  • v_sql 将是:BEGIN OPEN :1 FOR :2 USING 1,2;结尾;所有这些都将被传递给执行立即执行,它将执行 :1 和 :2 与输出游标变量和 v_script 的值(!)的绑定。是的 - 它会工作!我唯一抱怨的是错误处理程序。
  • @tv 哦,是的,确实如此,我很抱歉。我以前从未见过这样做过,是否有理由以这种方式编写它而不是我发布的更简单的版本?只是好奇。
  • 我需要传递一个字符串作为 USING ,一个基于某些 if 的在旅途中创建的字符串。如果有另一种方法可以根据一些 if 规则动态绑定变量,那么我很乐意听。你描述的方式 - 它是硬编码的 USING 参数,这对我来说完全不是:当我将附加子句附加到 v_script 时 - 然后你必须将第三个参数传递给 using ,这根本不起作用!跨度>
猜你喜欢
  • 1970-01-01
  • 2016-10-10
  • 2010-12-06
  • 2021-12-06
  • 1970-01-01
  • 1970-01-01
  • 2018-09-27
  • 2013-03-28
  • 2010-12-05
相关资源
最近更新 更多