2017-03-09 5 views
0

次のコードを実行しようとしましたが、実行即時ブロックで失敗しました。だから、構文が間違っていますか?なぜこの即時実行はこのPLS-00201エラーをスローしますか?

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は

答えて

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

ループボディの列名をハードコードする場合は、USER_TAB_COLUMNSを照会する価値はほとんどありませんすべて – APC

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のに対し、非表示の列に対して出力されていない行を行いますそれを見たくなければ明示的にフィルタリングしなければなりません。

+0

エラーは動的SQLから発生しています。カーソル内でも使用されている 'emp_no'を参照しています。コンパイルエラーが発生しますが、動的SQLのPLS-00201ではなくカーソルからのORA-00904が隠れていると思いますか? –

+0

@AlexPooleええ、私は他の答え(彼らは正しいように見える!)を見たが、隠れた列は関係なく正しく処理する必要があるので、とにかく私の答えを残すと思った。 – Boneist

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を使用しているはずです:)

+0

このようなバインド変数を持つレコードを使用できますか?12cでは新しくなっていますか? –

+0

ああ、良い点。私は私の答えを更新します。 – APC

関連する問題