2015-01-12 18 views
7

今日、コンパイルすべきではない面白いコードが出てきました。 FOR r IN ... LOOP内のSELECT ... INTO句を使用します。 Oracle 11iでコンパイルされるスクリプトは次のとおりです。このスクリプトは、パッケージでコンパイルされた実際のPL/SQLコードの短縮バージョンであり、本番環境で動作します。FOR r in(SELECT ... INTO ...)

create table tq84_foo (
    i number, 
    t varchar2(10) 
); 

insert into tq84_foo values (1, 'abc'); 
insert into tq84_foo values (2, 'def'); 

declare 

    rec tq84_foo%rowtype; 

begin 

    for r in (
    select  i,  t 
     into rec.i, rec.t -- Hmm??? 
     from tq84_foo 
) 
    loop 

    dbms_output.put_line('rec: i= ' || rec.i || ', t=' || rec.t); 

    end loop; 

end; 
/


drop table tq84_foo purge; 

出力、実行すると、次のとおりです。私は無事select文のINTO一部を削除することができ、2)この構築物は無効であるべきいずれかのことを

rec: i= , t= 
rec: i= , t= 

私は 1を信じる)または少なくとも未定義の挙動を示す。

私の2つの仮定は正しいですか?

+0

OracleドキュメントでSQL SELECT文が明示的に記述されていて、カーソルFORループに対してSELECT INTOが明示的に記述されていない場合は、特に注意してください。http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/cursor_for_loop_statement.htm#LNPLS1155 – Sathya

+1

私はこれまで気付いたことがありますが、サポートドキュメントのどこにでもそれへの参照が見つかりませんでした。私は 'into '部分が静かに無視されていることを確かめています - あなたは明示的に' rec'フィールドに値を設定することができ、ループの中でも後でも変更されません。残念ながら引用が必要です... –

+0

'INTO'節が削除されれば、すべてが完璧に動作します。値は' forループ 'からの' r.iとr.t'の出力で見ることができます。これはパーサが黙って無視することを証明します。 'DECLARE rec tq84_foo%rowTYPE; は におけるRの をBEGIN(、 トンrec.i INTO、rec.tを私を選択 - ???うーんtq84_foo FROM )を LOOP DBMS_OUTPUT.PUT_LINE ( 'REC:私は=' ||里|| '、t =' || rt ) ; END LOOP; END; / '本当に奇妙です! –

答えて

1

あなたの仮定は、部分的に正しいです:

1)はい、あなたは安全にSELECT文のINTO一部を削除することができます。しかし、あなたは、この形式にループ内の行を変更する必要があります。

dbms_output.put_line('rec: i= ' || r.i || ', t=' || r.t); 

それはr変数

2からデータを取得しますそのように)このコードに問題があることがSELECT ... INTOの構文です問合せが複数の行を戻す場合は失敗します。もし失敗しなければ、バグかもしれないし、予期しない動作をするでしょう。