有没有办法在 PL/SQL 中背靠背地运行多个过程,以便创建一个表,然后按照我的代码中的结构进行填充?

Posted

技术标签:

【中文标题】有没有办法在 PL/SQL 中背靠背地运行多个过程,以便创建一个表,然后按照我的代码中的结构进行填充?【英文标题】:Is there anyway to run multiple-procedures back-to-back in PL/SQL so that a table is created and then filled in as structured in my code? 【发布时间】:2020-04-22 22:32:47 【问题描述】:

我正在使用 Oracle SQL Developer,我正在尝试让下面的代码工作,但无法弄清楚。我尝试了多种不同的方法,包括实现 for 循环、立即执行、调度和重新编译。

BEGIN
  ORDER_STATUS_1_DROP_TABLE;    -- If the table exist, drop it
  ORDER_STATUS_2_CREATE_TABLE;  -- Create the table
  GRANT_NEWANALYTICS;           -- Grant users select access
  ORDER_STATUS_3_SCRIPT;        -- Run script to insert data into table
END;

代码试图做的是:

过程 1:如果存在则丢弃,否则跳过。如果在没有表的情况下运行此过程,我不想看到任何警告错误指出不存在表。此过程本身确实按预期工作。

create or replace PROCEDURE ORDER_STATUS_1_DROP_TABLE IS 
    table_does_not_exist EXCEPTION;
    PRAGMA EXCEPTION_INIT(table_does_not_exist, -942);
  BEGIN
    EXECUTE IMMEDIATE 'DROP TABLE <Table Name>';
  EXCEPTION
    WHEN table_does_not_exist then
    dbms_output.put_line( 'table dose not exist');
  END ORDER_STATUS_1_DROP_TABLE;

过程 2:一旦表被删除,这个过程就会用正确的 .我不希望看到“此表已存在”的任何错误,这就是过程 1 存在的部分原因。这本身就可以按预期工作。

create or replace PROCEDURE ORDER_STATUS_2_CREATE_TABLE IS
    v_sql LONG;
  BEGIN
    v_sql:= 'create table <Table Name>
      (<parameters>)';
  EXECUTE IMMEDIATE v_sql;
  END ORDER_STATUS_2_CREATE_TABLE;

过程 3:这只是让用户选择访问在最后一个过程中创建的表。此过程按预期工作。

create or replace PROCEDURE GRANT_NEWANALYTICS IS 
  BEGIN
    EXECUTE IMMEDIATE
      'GRANT SELECT ON <Table Name> TO <UserID>';
  END;

过程 4:这是一个复杂的查询。这是一个插入全选(表左连接到基于字段和条件等的其他几个表)。程序1-3运行后,这个程序本身没有问题运行,而是自己运行。

create or replace PROCEDURE ORDER_STATUS_3_SCRIPT IS 

  BEGIN
    DELETE FROM <Table Name>;
    INSERT INTO <Table Name>
    SELECT * FROM(<Multiple Table Joins>);
  END ORDER_STATUS_3_SCRIPT;

当我运行这样的程序时:

  BEGIN
   ORDER_STATUS_1_DROP_TABLE;    -- If the table exist, drop it
   ORDER_STATUS_2_CREATE_TABLE;  -- Create the table
   GRANT_NEWANALYTICS;           -- Grant users select access
   ORDER_STATUS_3_SCRIPT;        -- Run script to insert data into table
  END;

我收到以下错误报告:

Error report -
ORA-04068: existing state of packages has been discarded
ORA-04065: not executed, altered or dropped stored procedure "<user>.ORDER_STATUS_3_SCRIPT"
ORA-06508: PL/SQL: could not find program unit being called: "<user>.ORDER_STATUS_3_SCRIPT"
ORA-06512: at line 5
04068. 00000 -  "existing state of packages%s%s%s has been discarded"
*Cause:    One of errors 4060 - 4067 when attempt to execute a stored procedure.
*Action:   Try again after proper re-initialization of any application's state.

现在,如果我单独运行这些,它可以工作。所以如果我第一次运行这个:

 BEGIN
  ORDER_STATUS_1_DROP_TABLE;    -- If the table exist, drop it
  ORDER_STATUS_2_CREATE_TABLE;  -- Create the table
  GRANT_NEWANALYTICS;           -- Grant users select access
END;
<OUTPUT> PL/SQL procedure successfully completed.

然后是这个:

BEGIN
ORDER_STATUS_3_SCRIPT;        -- Run script to insert data into table
END;
<OUTPUT> <Query runs>

我没有问题。我想在一次扫描中运行这些程序集,并且可以在这样的想法上使用一些帮助。有人有想法么?

【问题讨论】:

为什么要删除表? 最好使用@Justin Cave 建议的包含上述过程和动态 SQL 的包 【参考方案1】:

如果您想将所有这些过程作为单个 PL/SQL 块的一部分运行,那么对您的表的每个引用都需要通过动态 SQL。所以ORDER_STATUS_3_SCRIPT 需要使用动态 SQL 来构建插入语句来填充表,而不是使用简单的静态 SQL。这显然是可能的,但它确实增加了脚本的复杂性。可能大幅。

拥有两个 PL/SQL 块,您已经证明了它们的工作原理,看起来要简单得多。

【讨论】:

删除和重新创建表在 Oracle 中基本上是一种反模式,而且从来没有必要。它将您用作一次性使用表(您的 3_script)在重新填充之前删除所有行。因此,与 insead 3_script 中的截断相比,删除和重新创建没有任何优势。这会将您的整个过程减少到 1 个脚本。另一种选择,取决于在 3_script 之后如何处理数据,可能只是创建一个全局临时表。无论哪种方式,ORDER_STATUS_3_SCRIPT 都是您需要的唯一脚本。 嗨贾斯汀。是的,我明白了。有时某些源字段不能从上游源获得,我是这样设计的,所以在过程中我可以注释掉当月不可用的任何字段。也许我可以想办法说如果字段不可用则为空。不得不考虑一些。感谢您的反馈!

以上是关于有没有办法在 PL/SQL 中背靠背地运行多个过程,以便创建一个表,然后按照我的代码中的结构进行填充?的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法在 Oracle 中刷新 PL/SQL 的输出?

有没有办法在 Oracle 中刷新 PL/SQL 的输出?

如何使用 PL/SQL 中的过程在表中插入多个值?

如何在pl / sql中同时在不同会话中执行存储过程

在pl sql中的单个变量中传递两个或多个参数[重复]

PL/SQL 过程和 Toad 执行?