【问题标题】:Convert a PL/SQL script to a stored procedure将 PL/SQL 脚本转换为存储过程
【发布时间】:2012-05-31 03:28:39
【问题描述】:

现在我正在将数据导入并转换到 Oracle 数据库中,如下所示:

  • 程序定期轮询特定文件夹,一旦找到文件,它就会执行一个批处理文件,该文件在 Python 和 bash 中进行一些简单的转换,然后调用 SQL*Loader 将 CSV 文件加载到临时表中。

  • 然后,批处理脚本调用 SQL 脚本(通过 SQLPlus)进行最终转换,并将转换后的数据插入主表中以用于各自的暂存表。

这种方法的问题是在 SQLPlus 端没有错误处理,例如。如果“insert into”语句由于违反约束(或任何其他原因)而失败,它仍将继续执行 SQL 脚本中包含的其余语句。

理想情况下,如果发生任何异常,我希望回滚所有更改并将异常的详细信息插入到 etl 日志表中。

存储过程似乎很适合,因为异常处理是内置的。但是,我在语法上苦苦挣扎——特别是我如何使用我的大 SQL 脚本(它们只是 INSERT INTO、UPDATE、CREATE、DROP、DELETE 等语句的组合)并将它们放入存储过程中基本错误处理。

我希望的是:

  • 一个快速而肮脏的假人指南,用于获取我令人沮丧的 PL/SQL 块并让它在存储过程中执行或
  • 提供相同功能的任何替代方案(如果存储过程不合适),即。一种执行一堆 SQL 语句并在其中任何语句引发异常时回滚的方法。

关于我的尝试 - 我尝试将部分 SQL 脚本复制到存储过程中,但它们总是无法编译,并出现错误“PLS-00103 在预期以下情况之一时遇到符号”。例如。

CREATE OR REPLACE PROCEDURE ETL_2618A AS 
   BEGIN
       DROP SEQUENCE "METER_REPORTING"."SEQ_2618"; 
       CREATE SEQUENCE SEQ_2618; 
END ETL_2618A;

Oracle 文档不是很容易访问,而且我在谷歌搜索/搜索 StackOverflow 方面运气不佳,但如果我遗漏了一些明显的东西,我深表歉意。

【问题讨论】:

  • 能否请您发布您的过程代码以及 oracle 返回的确切错误消息
  • 我已经提供了,请参阅帖子底部。完整的错误是:PLS-00103:在预期以下之一时遇到符号“DROP”:yadda yadda + PLS-00103:遇到符号“END”
  • 我应该注意,提供的程序代码代表了我试图在程序中工作的脚本的一小部分,但我认为一个小例子比发布整个脚本更好。
  • 这是一个语义细节,但您将 SQL 脚本转换为存储过程,而不是 PL/SQL 脚本。

标签: oracle plsql oracle10g


【解决方案1】:

要在 PL/SQL 中进行 DDL,您需要使用动态 sql。

CREATE OR REPLACE PROCEDURE testProc IS
   s_sql    VARCHAR2(500);
BEGIN
   s_sql := 'DROP SEQUENCE "METER_REPORTING"."SEQ_2618"';
   EXECUTE IMMEDIATE s_sql;


   s_sql := 'CREATE SEQUENCE "METER_REPORTING"."SEQ_2618"';
   EXECUTE IMMEDIATE s_sql;

EXCEPTION

   WHEN OTHERS THEN
       NULL;
end testProc;
/

【讨论】:

  • 谢谢。对 60-70 条语句执行此操作非常耗时,并且鉴于我不需要动态 SQL,我认为没有更简单的方法可以将错误处理作为 SQL 脚本的一部分,即使它没有不涉及使用存储过程?
  • 我发布的内容适用于 DDL ,对于 DML 你可以照常使用它们
  • @evanjd:是的,你需要你的 SQL 是动态的。 DDL 不能在 PL/SQL 中“直接”执行。
【解决方案2】:

如果你在 sqlplus 中运行脚本,你可以使用:

每当出现 sqlerror

控制发生错误时应该发生的事情。

http://docs.oracle.com/cd/B19306_01/server.102/b14357/ch12052.htm

【讨论】:

    【解决方案3】:

    向 PL/SQL 过程或脚本添加异常处理并不困难,但当然需要一些编码。这是您的程序,添加了一些非常基本的错误报告:

    CREATE OR REPLACE PROCEDURE ETL_2618A AS
      nCheckpoint  NUMBER;
    BEGIN
      nCheckpoint := 1;
    
      EXECUTE IMMEDIATE 'DROP SEQUENCE "METER_REPORTING"."SEQ_2618"';
    
      nCheckpoint := 2;
    
      EXECUTE IMMEDIATE 'CREATE SEQUENCE SEQ_2618';
    
      RETURN;
    EXCEPTION
      WHEN OTHERS THEN
        DBMS_OUTPUT.PUT_LINE('ETL_2618A failed at checkpoint ' || nCheckpoint ||
                             ' with error ' || SQLCODE || ' : ' || SQLERRM);
        RAISE;
    END ETL_2618A; 
    

    未在动物身上进行测试 - 你会是第一个! :-)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-12-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多