【问题标题】:PLS-00103: Encountered the symbol "end-of-file" in FlyWayPLS-00103:在 FlyWay 中遇到符号“文件结尾”
【发布时间】:2018-04-11 14:52:25
【问题描述】:

我们有一个数据库迁移脚本,通过 FlyWay 运行,它是 Java 应用程序的一部分。问题是一些客户拥有旧版本的应用程序,其中显示了一些表格和数据,而其他客户将安装此产品作为新解决方案。这些脚本必须每次都运行(解决问题和历史问题)。

事实上,我们在 SQL 中通过简单的检查来处理这个问题,如果表存在,然后执行其余的脚本。它适用于其他数据库(Postgres、MySQL、MS SQL)但不适用于 Oracle。经过几天的尝试和谷歌搜索,我开始把头发从头上扯下来。第一个问题是执行 DDL 语句(已经知道我不能这样做),现在是这个。

我们训练的目标是什么:

  1. 如果当前用户存在主表,则运行脚本(这就是我们 确定,如果所有其他表也存在)
  2. 我们需要为每个表创建一个备份表并复制其中的所有行(这就是我们执行 TRUNCATE 和 INSERT INTO 的原因,如果失败, 我们做 CREATE TABLE AS) - 这是呈现的代码应该做的,IF table_count > 0 THEN 和 END IF 内的代码块;每个呈现的表格都会重复 (11x)
  3. 然后我们运行清理脚本,该脚本会检查错误数据并清理它们(我们必须存储原始值以防万一 坏了)。
  4. 清理后的数据被复制到新表中(在之前的脚本中准备)。

总共有 10 个脚本,但这个总是失败。

代码如下:

DECLARE 
  table_count NUMBER;
  curr_user VARCHAR2(100);  
BEGIN
  SELECT
  sys_context('USERENV','SESSION_USER') INTO curr_user 
  FROM dual;

  SELECT count(*)
  INTO table_count
  FROM all_objects
  WHERE object_type IN ('TABLE', 'VIEW')
  AND object_name = 'main_table'
  AND owner = curr_user;

  IF table_count > 0 THEN
    BEGIN
      EXECUTE IMMEDIATE 'TRUNCATE TABLE some_table_backup';
      EXECUTE IMMEDIATE 'INSERT INTO some_table_backup
          SELECT *
          FROM some_table';
      EXCEPTION
      WHEN OTHERS THEN
      IF SQLCODE != -942
      THEN
        RAISE;
      ELSE
        EXECUTE IMMEDIATE 'CREATE TABLE some_table_backup AS SELECT * FROM some_table';
      END IF;
    END;

    BEGIN
      EXECUTE IMMEDIATE 'TRUNCATE TABLE some_table_backup2';
      EXECUTE IMMEDIATE 'INSERT INTO some_table_backup2
          SELECT *
          FROM some_table2';
      EXCEPTION
      WHEN OTHERS THEN
      IF SQLCODE != -942
      THEN
        RAISE;
      ELSE
        EXECUTE IMMEDIATE 'CREATE TABLE some_table_backup2 AS SELECT * FROM some_table2';
      END IF;
    END;   
.
.
.

  END IF;

EXCEPTION
  WHEN OTHERS
  THEN
  DBMS_OUTPUT.put_line(SQLERRM);
END;

错误如下:

ORA-06550:第 30 行,第 8 列:

PLS-00103:在预期以下情况之一时遇到符号“文件结尾”:

第 30 行是 END;结束 IF 之后;在脚本的第一个分区中。

【问题讨论】:

    标签: java oracle flyway


    【解决方案1】:

    看起来您的 FlyWay 版本不喜欢嵌套的 PL/SQL 块。我会尝试添加匿名块标签:

    DECLARE 
      table_count NUMBER;
      curr_user VARCHAR2(100);  
    BEGIN
      SELECT
      sys_context('USERENV','SESSION_USER') INTO curr_user 
      FROM dual;
    
      SELECT count(*)
      INTO table_count
      FROM all_objects
      WHERE object_type IN ('TABLE', 'VIEW')
      AND object_name = UPPER('main_table')    --here I added UPPER
      AND owner = curr_user;
    
      IF table_count > 0 THEN
        <<name1>>
        BEGIN
          EXECUTE IMMEDIATE 'TRUNCATE TABLE some_table_backup';
          EXECUTE IMMEDIATE 'INSERT INTO some_table_backup
              SELECT *
              FROM some_table';
          EXCEPTION
          WHEN OTHERS THEN
          IF SQLCODE != -942
          THEN
            RAISE;
          ELSE
            EXECUTE IMMEDIATE 'CREATE TABLE some_table_backup AS SELECT * FROM some_table';
          END IF;
        END name1;
    
        <<name2>>
        BEGIN
          EXECUTE IMMEDIATE 'TRUNCATE TABLE some_table_backup2';
          EXECUTE IMMEDIATE 'INSERT INTO some_table_backup2
              SELECT *
              FROM some_table2';
          EXCEPTION
          WHEN OTHERS THEN
          IF SQLCODE != -942
          THEN
            RAISE;
          ELSE
            EXECUTE IMMEDIATE 'CREATE TABLE some_table_backup2 AS SELECT * FROM some_table2';
          END IF;
        END name2;   
    
    
      END IF;
    
    EXCEPTION
      WHEN OTHERS
      THEN
      DBMS_OUTPUT.put_line(SQLERRM);
    END;
    /
    

    或者,您可以通过改变方法来避免嵌套的 PL/SQL 块。

    您可以轻松地检查表是否存在,然后执行操作,而不是先尝试做某事并处理异常。这样就根本不需要嵌套的 PL/SQL 块。

    第二种选择是使用动态 SQL:

    DECLARE 
      table_count NUMBER;
      curr_user VARCHAR2(100);  
    BEGIN
      SELECT
      sys_context('USERENV','SESSION_USER') INTO curr_user 
      FROM dual;
    
      SELECT count(*)
      INTO table_count
      FROM all_objects
      WHERE object_type IN ('TABLE', 'VIEW')
      AND object_name = UPPER('main_table')
      AND owner = curr_user;
    
      IF table_count > 0 THEN
    
        EXECUTE IMMEDIATE q'{
        BEGIN
          EXECUTE IMMEDIATE 'TRUNCATE TABLE some_table_backup';
          EXECUTE IMMEDIATE 'INSERT INTO some_table_backup
              SELECT *
              FROM some_table';
          EXCEPTION
          WHEN OTHERS THEN
          IF SQLCODE != -942
          THEN
            RAISE;
          ELSE
            EXECUTE IMMEDIATE 'CREATE TABLE some_table_backup AS SELECT * FROM some_table';
          END IF;
        END;}';
    
        EXECUTE IMMEDIATE q'{
        BEGIN
          EXECUTE IMMEDIATE 'TRUNCATE TABLE some_table_backup2';
          EXECUTE IMMEDIATE 'INSERT INTO some_table_backup2
              SELECT *
              FROM some_table2';
          EXCEPTION
          WHEN OTHERS THEN
          IF SQLCODE != -942
          THEN
            RAISE;
          ELSE
            EXECUTE IMMEDIATE 'CREATE TABLE some_table_backup2 AS SELECT * FROM some_table2';
          END IF;
        END;}';   
    
      END IF;
    
    EXCEPTION
      WHEN OTHERS
      THEN
      DBMS_OUTPUT.put_line(SQLERRM);
    END;
    

    请注意q'{}' 文本字面量的用法,它允许处理' 而无需复制它们。

    使用 FlyWay 4.2.0(从命令行调用),两个示例都可以正常工作。

    【讨论】:

    • 感谢您的回复。不幸的是,第一个选项没有改变,第二个选项在另一个地方引发了另一个错误。现在还有另一个对我来说毫无意义的错误:ORA-06550:第 14 行,第 7 列:PLS-00103:在预期以下之一时遇到符号“文件结尾”
    • @FráňaŠpaček 有趣。我将使用最近的机会检查带有 Flyway 的嵌套块。无论如何,您可以按照我的建议重写您的代码,而无需嵌套块。
    • 是的,我可能会尝试。我只是好奇,为什么这不起作用,因为我只有使用 MySQL 和 Postgres 的经验,而这很容易实现。
    • @FráňaŠpaček 好的,带有动态 SQL 的版本应该可以工作。我添加了缺少的; 并在我的本地机器上进行了测试(Oracle 12c + 最新的 flyway)
    • @FráňaŠpaček:不,我没有。我其实很欣赏这种技术。
    猜你喜欢
    • 2016-02-12
    • 2023-03-21
    • 1970-01-01
    • 1970-01-01
    • 2011-03-04
    • 2018-01-23
    • 2016-11-05
    相关资源
    最近更新 更多