我试图运行以下代码,并且在Execute即时块中失败。所以,语法我会出错吗?
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;
我得到此错误
pls-00201:必须声明标识符emp_rec.emp_no
您的emp_rec
变量是本地PL/SQL记录。当您执行此操作时,即使使用静态字段名称参考:
execute immediate 'begin :x := emp_rec.emp_no; end;'
动态SQL在调用它的块的单独上下文中运行。然后,您在该上下文中运行一个新的匿名PL/SQL块。
来自外部匿名块,特别是emp_rec
的任何变量都不范围与动态SQL上下文。它们只是不存在试图将值分配给:x
的代码。
您可能会使用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;
/
尽管正如@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;
/
execute立即语句中的 emp_rec
与调用代码中的emp_rec
不同的名称空间存在。
不确定您要实现的目标,但可能是这样的:
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;
注意:我在12C中测试了此代码的一个版本,并且在那里确实有效。las,它在11gr2中不起作用(大概也是更早的版本);它投掷PLS-00457
。尽管如此,除了有深度口袋的人以外,11gr2几乎是不支持的,每个人现在都应该使用12c:)
我的猜测是您在EMP表中有一个隐藏的列。这些是被标记为未使用但尚未下降的列,因此,它们无法从中选择。
您可以更新光标以使用:
select column_name, data_type
from user_tab_cols
where table_name = 'EMP'
and hidden_column != 'NO'
或:
select column_name, data_type
from user_tab_columns
where table_name = 'EMP';
注意两个查询中使用的不同视图名称-USER_TAB_COLUMNS未输出隐藏列的行,而User_tab_cols则必须明确地将它们明确过滤出来。