How to execute a local procedure using execute immedate?

后端 未结 2 1180
后悔当初
后悔当初 2021-01-25 07:36

I have the below PL SQL Block:

WHENEVER SQLERROR EXIT 1
SET SERVEROUTPUT ON   

DECLARE
v_sql VARCHAR2(500);
f1 VARCHAR2(20) := \'abc\';
p_procname VARCHAR2 (30)         


        
相关标签:
2条回答
  • 2021-01-25 08:14

    As Amarillo said you can't execute a locally-defined procedure dynamically, as it doesn't exist in the SQL scope the dynamic section will be using.

    The situation you describe is that all the procedures are defined in the anonymous block's DECLARE section and you are running a query that tells you which of them to execute - and presumably which also gives you the arguments to pass. You can just use an if/else construct or a case statement to execute the appropriate procedures, something like:

    DECLARE
      ...
    BEGIN
      FOR data IN (SELECT procname, arg1, arg2, ... from <your_query>) LOOP
        CASE data.procname
          WHEN 'OPENLOG' THEN
            openlog(data.arg1);
          WHEN 'WRITELOG' THEN
            writelog(data.arg1, data.arg2);
          WHEN ...
            ...
          ELSE
             -- handle/report an invalid procedure name
             -- or skip the `ELSE` and let CASE_NOT_FOUND be thrown
        END CASE;
      END LOOP;
    END;
    /
    

    You just need one WHEN condition and appropriate procedure call for each procedure. You can also either have an ELSE to catch any unexpected procedure names or let the CASE_NOT_FOUND exception (ORA-06592) be thrown, depending on what you need to happen if that ever occurs.

    0 讨论(0)
  • 2021-01-25 08:16

    Use it like this:

    DECLARE
    v_sql VARCHAR2(500);
    f1 VARCHAR2(20) := 'abc';
    p_procname VARCHAR2 (30) := 'OPENLOG';
    
       PROCEDURE OPENLOG (file_name IN VARCHAR2)
       IS
       BEGIN
          NULL;
       END;    
    
    BEGIN
    DBMS_OUTPUT.PUT_LINE('Begin');
    openlog(f1);
    END;
    

    You don't need to use execute immediate with begin end in this case, because you have the procedure in the declare section.

    The other way is create the procedure as a database object like this:

           CREATE PROCEDURE OPENLOG (file_name IN VARCHAR2)
           IS
           BEGIN
              NULL;
           END;  
    

    And the you can use execute immediate:

    DECLARE
    v_sql VARCHAR2(500);
    f1 VARCHAR2(20) := 'abc';
    p_procname VARCHAR2 (30) := 'OPENLOG';
    
    BEGIN
    DBMS_OUTPUT.PUT_LINE('Begin');
    v_sql := 'BEGIN ' || p_procname || '(:a); END;';
    EXECUTE IMMEDIATE v_sql USING IN f1;
    END;
    
    0 讨论(0)
提交回复
热议问题