残念ながら、INSERTステートメントの return into句は、 values句でのみ使用できるため、これはそれほどきれいではありません。
挿入しているデータを 2 回選択せずに再利用したい場合は、再利用できる場所に配置する必要があります。これは、GLOBAL TEMPORARY TABLE (GTT)またはユーザー定義型のいずれかです。
個人的には、タイプの方が柔軟性があると思うので、タイプの方が好きです。何をしたいかは、その後にどのような処理を行う必要があるかによって異なります。結果に対して SQL を実行する必要がある場合は、GTT の方が適しています。
ユーザー定義型で何かをしたい場合は、それをBULK COLLECTと組み合わせてください。次のようになります。
ポイントは、作成する SELECT ステートメントであるカーソルを宣言することです。次に、その SELECT ステートメントの値を保持できる型を宣言します。次に、すべてのデータをその型に収集します。それが完了したら、どこにでも INSERT して、必要な他の操作を実行できます。一般に、できることはすべて PL/SQL ではなく SQL で行う方がよいでしょう。PL/SQL を使用した方が速いという確信がない限り、これ以上の処理は行わないでください。
declare
cursor c_stuff is
select a, b, ..., fn(x, y) as fn
from somewhere;
type t__stuff is table of c_stuff%rowtype index by binary_integer;
t_stuff t__stuff;
l_new_stuff varchar2(100);
begin
open c_stuff;
fetch c_stuff bulk collect into t_stuff;
close t_stuff;
forall i in t_stuff.first .. t_stuff.last
insert into somewhere_else values (t_stuff(i));
for i in t_stuff.first .. t_stuff.last loop
l_new_stuff := l_new_stuff || t_stuff(i).fn;
end loop;
...
GTT ルートを下ると、少し楽に見えます。SELECT ステートメントによって返されるものと同じデータ型を持つテーブルを作成します。
create global temporary table gtt_stuff (
a number
, b ...
, fn ... )
on commit delete rows;
次に、このテーブルに挿入します。テーブル内のデータを操作して、通常のテーブルと同じように利用できます。DELETE ROWS を使用した場合はトランザクションが終了するまで、PRESERVE ROWS を指定した場合はセッションが終了するまで、データは存続します。
の結果を連結していると言うfn()
ので、おそらく次のようになります。
select listagg(fn) within group (order by 1)
into l_new_stuff
from gtt_stuff;
また、GTTとテーブルに同時にINSERT できるように、マルチテーブル INSERT を使用できるコメントの David Aldridge の (素晴らしい) 提案にも注意してください。
insert all
into gtt_stuff values (a, ..., fn) -- only necessary columns
into somewhere_else values (a, b, ..., fn)
select a, b, ..., fn
from somewhere