我们有一个数据库迁移脚本,它们通过FlyWay运行,它是Java应用程序的一部分。问题是,一些客户拥有较旧版本的应用程序,其中会显示一些表格和数据,而其他客户将安装此产品作为新解决方案。这些脚本必须每次都运行(解决方案问题和历史问题)。
事实上,我们通过简单检查在SQL中处理这个问题,如果表存在则执行其余的脚本。它适用于其他数据库(Postgres,MySQL,MS SQL),但不适用于Oracle。经过几天的尝试和谷歌搜索,我开始撕掉我的头发。第一个问题是执行DDL语句(已经学会了我不能这样做),现在就这样了。
我们要实现什么目标:
总共有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;在END IF之后;在脚本的第一个分区。
答案 0 :(得分:2)
看起来您的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(从命令行调用),两个示例都可以正常工作。