PLS-00103: 在 FlyWay 中遇到符号 "end-of-file"
PLS-00103: Encountered the symbol "end-of-file" in FlyWay
我们有一个数据库迁移脚本,它是 运行 通过 FlyWay 的,它是 Java 应用程序的一部分。问题是一些客户使用旧版本的应用程序,其中显示了一些 table 和数据,而其他客户将安装此产品作为新解决方案。这些脚本每次都必须 运行(解决方案问题和历史问题)。
事实上,我们在 SQL 中通过简单检查来处理这个问题,如果 table 存在,然后执行脚本的其余部分。它适用于其他数据库(Postgres、MySQL、MS SQL)但不适用于 Oracle。经过几天的尝试和谷歌搜索,我开始把头发从头上扯下来。第一个问题是执行 DDL 语句(我已经知道我不能那样做)现在是这个。
我们训练的目标是什么:
- 运行 脚本如果 main table 存在于当前用户(这就是我们的方式
确定,如果所有其他 table 也存在)
- 对于每个 table 我们需要创建一个备份 table 并复制其中的所有行(这就是我们执行 TRUNCATE 和 INSERT INTO 的原因,如果失败,
我们做 CREATE TABLE AS) - 这是呈现的代码应该做的,IF table_count > 0 THEN 和 END IF 内的代码块;每出现一次 table 重复一次 (11x)
- 然后我们 运行 清理脚本,它检查坏数据并清理它们(我们必须存储原始值以防万一
变坏了)。
- 清理后的数据被复制到新的 table 中(在之前的脚本中准备)。
总共有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: line 30, column 8:
PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following:
第30行结束;在 END IF 之后;在脚本的第一个分区中。
您的 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 块。
您可以轻松地检查 table 是否存在,然后执行操作,而不是先尝试做某事并处理异常。这样就根本不需要嵌套 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(从命令行调用)两个示例都可以正常工作。
我们有一个数据库迁移脚本,它是 运行 通过 FlyWay 的,它是 Java 应用程序的一部分。问题是一些客户使用旧版本的应用程序,其中显示了一些 table 和数据,而其他客户将安装此产品作为新解决方案。这些脚本每次都必须 运行(解决方案问题和历史问题)。
事实上,我们在 SQL 中通过简单检查来处理这个问题,如果 table 存在,然后执行脚本的其余部分。它适用于其他数据库(Postgres、MySQL、MS SQL)但不适用于 Oracle。经过几天的尝试和谷歌搜索,我开始把头发从头上扯下来。第一个问题是执行 DDL 语句(我已经知道我不能那样做)现在是这个。
我们训练的目标是什么:
- 运行 脚本如果 main table 存在于当前用户(这就是我们的方式 确定,如果所有其他 table 也存在)
- 对于每个 table 我们需要创建一个备份 table 并复制其中的所有行(这就是我们执行 TRUNCATE 和 INSERT INTO 的原因,如果失败, 我们做 CREATE TABLE AS) - 这是呈现的代码应该做的,IF table_count > 0 THEN 和 END IF 内的代码块;每出现一次 table 重复一次 (11x)
- 然后我们 运行 清理脚本,它检查坏数据并清理它们(我们必须存储原始值以防万一 变坏了)。
- 清理后的数据被复制到新的 table 中(在之前的脚本中准备)。
总共有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: line 30, column 8:
PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following:
第30行结束;在 END IF 之后;在脚本的第一个分区中。
您的 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 块。
您可以轻松地检查 table 是否存在,然后执行操作,而不是先尝试做某事并处理异常。这样就根本不需要嵌套 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(从命令行调用)两个示例都可以正常工作。