[英]Why does Execute Immediate throw this PLS-00201 error?
I was trying to run the following code and it failed in the execute immediate block. 我试图运行以下代码,但在立即执行代码块中失败。 So, am I going wrong with the syntax?
所以,我语法有问题吗?
DECLARE
l_data long;
emp_rec EMP%rowtype;
begin
select * INTO emp_rec from EMP A WHERE A.EMP_NO = '001322';
for x in ( select column_name, data_type
from user_tab_columns
where table_name = 'EMP' )
loop
execute immediate
'begin
:x := emp_rec.' || x.column_name || ';
end;' using OUT l_data;
dbms_output.put_line( x.column_name || ' = ' || l_data );
end loop;
end;
I get this error 我得到这个错误
PLS-00201: Identifier EMP_REC.EMP_NO must be declared
PLS-00201:必须声明标识符EMP_REC.EMP_NO
Your emp_rec
variable is a local PL/SQL record. 您的
emp_rec
变量是本地PL / SQL记录。 When you do this, even with a static field name reference: 当您执行此操作时,即使使用静态字段名称引用也是如此:
execute immediate 'begin :x := emp_rec.emp_no; end;'
the dynamic SQL runs in a separate context to the block that calls it. 动态SQL在调用它的块的单独上下文中运行。 You then run a new anonymous PL/SQL block within that context.
然后,您在该上下文中运行一个新的匿名PL / SQL块。
Any variables from your outer anonymous block, specifically emp_rec
here, are out of scope to the dynamic SQL context. 外部匿名块中的任何变量(这里特别是
emp_rec
)都超出了动态SQL上下文的范围。 They just do not exist to the code that is trying to assign the value to :x
. 它们只是不存在于试图将值分配给
:x
的代码中。
You could possibly do something with dbms_sql
to make this dynamic, but if you know the table columns it would be easier to do: 您可以使用
dbms_sql
进行某些dbms_sql
以使其动态化,但是如果您知道表列,则将更容易做到:
declare
l_data varchar2(4000); -- long is deprecated; how big does this really need to be?
emp_rec EMP%rowtype;
begin
select * INTO emp_rec from EMP A WHERE A.EMP_NO = '001322';
for x in (
select column_name, data_type
from user_tab_columns
where table_name = 'EMP'
)
loop
case x.column_name
when 'EMP_NO' then
l_data := emp_rec.emp_no;
-- when clauses for each column in your real table
when 'FIRST_NAME' then
l_data := emp_rec.first_name;
when 'LAST_NAME' then
l_data := emp_rec.last_name;
-- list other columns and assignments
-- else ...
end case;
dbms_output.put_line( x.column_name || ' = ' || l_data );
end loop;
end;
/
although as @APC pointed out, the loop is now a bit pointless, since you can just do: 尽管正如@APC所指出的那样,循环现在没有任何意义,因为您可以执行以下操作:
declare
emp_rec EMP%rowtype;
begin
select * INTO emp_rec from EMP A WHERE A.EMP_NO = '001322';
dbms_output.put_line( 'EMP_NO = ' || emp_rec.emp_no );
dbms_output.put_line( 'FIRST_NAME = ' || emp_rec.first_anme );
dbms_output.put_line( 'LAST_NAME = ' || emp_rec.last_name );
-- ... any other columns you want to show
end;
/
The emp_rec
in the EXECUTE IMMEDIATE statement exists in a different namespace from the emp_rec
in the calling code. 该
emp_rec
在EXECUTE IMMEDIATE语句存在于从不同的命名空间emp_rec
调用代码。
Not sure exactly what you're trying to achieve but it might be something like this: 不确定确切要达到的目标,但是可能是这样的:
DECLARE
l_data long;
emp_rec EMP%rowtype;
begin
select * INTO emp_rec from EMP A WHERE A.EMP_NO = '001322';
for x in ( select column_name, data_type
from user_tab_columns
where table_name = 'EMP' )
loop
execute immediate
'declare
lrec EMP%rowtype;
begin
lrec := :emp_rec;
:x := lrec.' || x.column_name || ';
end;' using emp_rec, OUT l_data;
dbms_output.put_line( x.column_name || ' = ' || l_data );
end loop;
end;
Note: I tested a version of this code in 12C and it does work there. 注意:我在12C中测试了此代码的版本,并且在该版本中可以正常工作。 Alas it doesn't work in 11gR2 (and presumably earlier versions too);
las,它不适用于11gR2(可能也是早期版本); it hurls
PLS-00457
. 它抛出
PLS-00457
。 Still, 11gR2 is pretty much out of support except for folks with deep pockets, everybody ought to be using 12c by now:) 尽管如此,除了财力雄厚的人以外,11gR2几乎没有支持,现在每个人都应该使用12c :)
My guess would be that you have a hidden column in your emp table. 我的猜测是您的emp表中有一个隐藏的列。 Those are columns that've been marked as unused but not yet dropped, and as such, they are not available to be selected from.
这些列已被标记为未使用但尚未删除,因此不能从中选择。
You could update your cursor to use: 您可以更新光标以使用:
select column_name, data_type
from user_tab_cols
where table_name = 'EMP'
and hidden_column != 'NO'
or: 要么:
select column_name, data_type
from user_tab_columns
where table_name = 'EMP';
Note the different view name used in both queries - user_tab_columns doesn't output rows for hidden columns, whereas user_tab_cols does so you have to explicitly filter them out if you don't want to see them. 请注意两个查询中使用的视图名称不同-user_tab_columns不会为隐藏列输出行,而user_tab_cols会输出,因此如果您不想看到它们,则必须明确地将其过滤掉。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.