2012-12-06 67 views
2

我有一個oracle程序,它調用其他幾個程序。在Oracle過程中運行DDL - ORA-06508 - 如何在運行時重新編譯?

PROCEDURE1
過程2
PROCEDURE3
..

現在發生的事情是PROCEDURE2是一些從屬表執行DDL(EXECUTE IMMEDIATE 'DDL PROCESS')在隨後的步驟3和以後使用。這運行良好,直到它遇到PROCEDURE3它投擲ORA-06508 - Program/Unit being called not found

我們不能修改它不使用DDL,我們必須使用它們。我試過在DDL語句後重新編譯,但在PROCEDURE1PROCEDURE2中都不起作用(ALTER PROCEDURE PROCEDURE3 RECOMPILE)。

我懷疑PROCEDURE1本身變得無效,編譯運行時會導致無限循環。我試過了,不起作用。

所以我需要使用一些技巧,使DDL在依賴對象上完成後,這些過程在運行時再次生效。

預先感謝誰參與回答。

+0

你應該嘗試撥打匿名BLOKS的程序。 –

+0

@ user1881540:您正在做什麼ddl更改,如創建表?並在程序3中使用該表。請發佈代碼。 –

回答

2

在這種情況下,在許多其他情況下,會更好地創建一個包,而不是一堆獨立的程序。包打破依賴鏈。這裏有一個例子:

SQL> create table tb_t(
    2 col1 number 
    3 ) 
    4 ; 

    Table created 
  1. 單機程序

    SQL> create or replace procedure Proc1 
        2 is 
        3 begin 
        4 execute immediate 'alter table tb_t add (col2 number)'; 
        5 end; 
        6/
    

    過程中創建

    SQL> create or replace procedure Proc2 
    2 is 
    3 l_var number; 
    4 begin 
    5 select count(*) 
    6  into l_var 
    7  from tb_t; 
    8 dbms_output.put_line(to_char(l_var)); 
    9 end; 
    10/
    
    Procedure created 
    
    SQL> begin 
        2 proc1; 
        3 proc2; 
        4 end; 
        5/
    

,我們越來越

 ORA-06508: PL/SQL: could not find program unit being called 
  1. SQL> create or replace package test_pkg 
        2 is 
        3 procedure proc1; 
        4 procedure proc2; 
        5 end; 
        6/
    
    Package created 
    
    SQL> create or replace package body test_pkg 
        2 is 
        3 procedure proc1 
        4 is 
        5 begin 
        6  execute immediate 'alter table tb_t add (col3 number)'; 
        7 end; 
        8 
        9 procedure proc2 
    10 is 
    11  l_var number; 
    12 begin 
    13  select count(*) 
    14  into l_var 
    15  from tb_t; 
    16  dbms_output.put_line(to_char(l_var)); 
    17 end; 
    18 
    19 end; 
    20/
    
    Package body created 
    
    
    SQL> begin 
        2 test_pkg.proc1; 
        3 test_pkg.proc2; 
        4 end; 
        5/
    
        0 
    
        PL/SQL procedure successfully completed 
    
+0

如果我不想創建一個包,該怎麼辦? – user1881540

+0

你能找到另一種方法嗎? – user1881540

+0

@ user1881540'如果我不想創建一個包'。爲什麼不?如果你真的不想創建一個包,你可以使用'execute immediate'語句('execute immediate begin proc1; end;'(對於pl/sql塊中的每個過程)),這也打破了依賴關係跟蹤。 [看看這個](http://stackoverflow.com/questions/12409189/compiling-invalid-oracle-procedures/12409857#12409857)。但是使用一個軟件包會更好。 –

0
alter procedure PX3 compile; -- not "recompile" 

這按預期工作:

set serveroutput ON 

create table X as select 42 A from DUAL; 

create procedure PX3 
as 
    a int; 
begin 
    select max(A) into a from X; 
    dbms_output.put_line(a); 
end; 
/

create procedure PX2 
as 
begin 
    execute immediate 'alter table X add (B int)'; 
    execute immediate 'alter procedure PX3 compile'; 
    PX3; 
end; 
/

create procedure PX1 
as 
begin 
    PX2; 
end; 
/

begin 
    PX1; 
end; 
/

drop procedure PX1; 
drop procedure PX2; 
drop procedure PX3; 
drop table X; 
+0

這不起作用。我已經嘗試過使用compile語句 – user1881540

+0

那麼,我提供的代碼在放入文件testcase.sql時工作,並在連接到Oracle 9服務器時在SQL * Plus中執行。 它在你的系統上工作嗎?如果它有效,你的代碼在做什麼不同? – colemar

0

如果我沒有弄錯,甲骨文9是更加嚴格的依賴和無效相比甲骨文> = 10。

我在Oracle 9中有幾個程序和/或包在他們依賴的表上執行DDL的包。 我得出的結論是,最實際的解決方案是使它們不依賴於那些表而不是。 也就是說而不是做靜態SQL

select COL1 into my_var from MY_CHANGING_TABLE ...; 

做動態SQL

execute immediate 'select COL1 from MY_CHANGING_TABLE ...' into my_var;