Joh*_*tam 3 oracle plsql sqlplus
我有以下PL/SQL脚本,我试图通过SQL*Plus运行:
DECLARE
table_exists number;
sequence_exists number;
sequence_start number;
BEGIN
select count(*) into sequence_exists
from all_sequences
where sequence_name='DBSEQ';
select count(*) into table_exists
from dba_tables
where table_name='DBTABLE';
IF sequence_exists = 0 AND table_exists > 0 THEN
select MAX(ID) + 1 into sequence_start from DBTABLE;
ELSE
sequence_start := 1;
END;
IF sequence_exists = 0 THEN
execute immediate 'CREATE SEQUENCE DBSEQ
start with ' || sequence_start || '
increment by 1
nomaxvalue';
END IF;
END;
Run Code Online (Sandbox Code Playgroud)
(这有点最小化,以显示实际失败的部分).
问题是排
select MAX(ID) + 1 into sequence_start from DBTABLE;
Run Code Online (Sandbox Code Playgroud)
失败的"PL/SQL:ORA-00942:表或视图不存在",因为该表不存在(我已经验证table_exists变量实际上是0).所以基本上,即使if子句没有执行,select运行(或至少失败).我还验证了if子句确实失败了,用例如创建一个表来替换select,这在运行脚本后不存在.
我也尝试捕获异常,做这样的事情:
BEGIN
select MAX(ID) + 1 into sequence_start from DBTABLE;
EXCEPTION
WHEN OTHERS THEN
sequence_start := 1;
END;
Run Code Online (Sandbox Code Playgroud)
但那产生了同样的错误.
那么,select语句有什么特别的东西可以让它在其他任何东西之前运行吗?我该如何解决我的问题?
问题是Oracle必须先编译块才能运行它.编译块的一部分涉及解析所有静态引用.如果您对不存在的表有引用,则该块将无法编译,因此无法运行.您的异常处理程序不执行任何操作,因为它是编译错误,而不是执行错误.
如果希望块引用编译块时可能不存在的表,则需要使用动态SQL.
EXECUTE IMMEDIATE 'select max(id) from dbtable'
INTO sequence_start;
Run Code Online (Sandbox Code Playgroud)
这将允许块成功编译,因为Oracle不需要解析动态SQL语句中的引用.如果您的代码在dbtable不存在时尝试执行动态SQL语句,您将收到运行时错误(您可以使用异常处理程序捕获).