问题描述
我有像下面这样的 PLsql 块,它添加一个虚拟列,进行更新,然后删除并重命名列
MenuItem
第一个立即执行语句成功,但新创建的列上的以下 UPDATE 语句失败并显示以下错误
BEGIN
NULL;
EXECUTE IMMEDIATE 'ALTER TABLE TESTMISMATCH ADD (TEMP_745634_1 VARCHAR2(4000 BYTE))';
UPDATE TESTMISMATCH SET TEMP_745634_1=TO_CHAR(A);
EXECUTE IMMEDIATE 'ALTER TABLE TESTMISMATCH DROP COLUMN A';
EXECUTE IMMEDIATE 'ALTER TABLE TESTMISMATCH RENAME COLUMN TEMP_745634_1 TO A';
End;
但是如果我在没有 plsql 块的情况下运行相同的语句,则所有语句都会成功执行,如下所示。
ORA-06550: line 4,column 25:
PL/sql: ORA-00904: "TEMP_745634_1": invalid identifier
ORA-06550: line 4,column 1:
我最初的怀疑是关于在 First“Execute Immediate”语句和 Update 语句之间发生的 PLsql 上下文和 sql 上下文切换。
解决方法
问题是 Oracle 必须先编译 PL/SQL 块,然后才能执行它。当它尝试编译块时,它发现 temp_745634_1
不是有效的列名并抛出错误。这发生在 Oracle 甚至可以尝试执行包括 execute immediate
在内的单个语句之前。
如果要在创建它的同一 PL/SQL 块中引用新创建的列,则需要将编译推迟到运行时。为此,您需要使 update
语句使用动态 SQL。因此,如果您执行 execute immediate 'update ...
,PL/SQL 块将起作用。
看起来您在第一步中所做的更改在块结束之前是不可见的。
这对你有帮助
BEGIN
EXECUTE IMMEDIATE 'ALTER TABLE TESTMISMATCH ADD (TEMP_745634_1 VARCHAR2(4000 BYTE))';
execute immediate 'UPDATE TESTMISMATCH SET TEMP_745634_1=TO_CHAR(''A'')';
EXECUTE IMMEDIATE 'ALTER TABLE TESTMISMATCH DROP COLUMN A';
EXECUTE IMMEDIATE 'ALTER TABLE TESTMISMATCH RENAME COLUMN TEMP_745634_1 TO A';
End;