我试图运行以下代码,但是在执行立即块中失败了。那么,我的语法错了吗?
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
答案 0 :(得分:3)
您的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;
/
答案 1 :(得分:2)
EXECUTE IMMEDIATE语句中的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中测试了此代码的一个版本,它在那里工作。唉它在11gR2中不起作用(也可能是早期的版本);它投掷PLS-00457
。尽管如此,11gR2几乎没有支持,除了有大笔资金的人,现在每个人都应该使用12c:)
答案 2 :(得分:0)
我的猜测是你的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会这样做,因此如果您不想看到它们,则必须明确过滤它们。