我的包装程序看起来像这样:
Procedure A
BEGIN;
Procedure B
Procedure C
END;
/
过程B删除并重新创建过程C中使用的表。由于这个原因,我得到以下错误:
ERROR at line 1:
ORA-04068: existing state of packages has been discarded ORA-04065: not executed, altered or dropped stored procedure "SCHEMA.PROCEDURE C"
ORA-06508: PL/SQL: could not find program unit being called: "SCHEMA.PROCEDURE C"
ORA-06512: at "SCHEMA.PROCEDURE A", line 4
ORA-06512: at line 1
如何让这个程序运作?
答案 0 :(得分:2)
所以你的proc在执行期间变得无效,这就是你需要重新编译过程C的原因。为了实现这一点,你可以调用动态SQL语句:
EXECUTE IMMEDIATE 'ALTER PROCEDURE my_procedure COMPILE';
Procedure_A IS
BEGIN;
Procedure_B;
EXECUTE IMMEDIATE 'ALTER PROCEDURE Procedure_C COMPILE';
Procedure_C;
END;
/
答案 1 :(得分:1)
我建议使用动态SQL在过程C中调用DML。通过删除依赖项,不会使任何内容失效。这可能比动态重新编译代码或动态运行代码并捕获所有异常更可靠。
您可以在下面的示例代码中看到这一点。在过程C中注释掉第10行的静态SQL调用以复制错误。
drop table drop_me;
create table drop_me(id number);
create or replace procedure C is
v_count number;
begin
--Static SQL would fail with this error:
-- ORA-04068: existing state of packages has been discarded
-- ORA-04065: not executed, altered or dropped stored procedure "JHELLER.C"
-- ORA-06508: PL/SQL: could not find program unit being called: "JHELLER.C"
-- ORA-06512: at "JHELLER.A", line 4
-- ORA-06512: at line 2
--select count(*) into v_count from drop_me;
--Dynamic SQL runs correctly:
execute immediate 'select count(*) from drop_me' into v_count;
end;
/
create or replace procedure B is
begin
execute immediate 'drop table drop_me purge';
execute immediate 'create table drop_me(id number)';
end;
/
create or replace procedure A is
begin
B;
C;
end;
/
begin
A;
end;
/
但我同意Alex Poole的观点,几乎可以肯定有一种更好的方法可以做到这一点,而无需删除和重新创建对象。我可以想到为什么DROP
和CREATE
可能比TRUNCATE
和INSERT
运行得更快的几个原因,但仅仅是因为一些奇怪的副作用,比如掉线不好表统计。更多地调查差异,你可能会找到真正的原因。
答案 2 :(得分:0)
你可以做类似的事情。
begin
procedureB;
begin
execute immediate 'begin procedureC; end;';
exception when others then
execute immediate 'begin procedureC; end;';
end;
end;