私の最後の質問から続けて( Oracle PL/SQLのテーブル変数? )...
配列/テーブルに値がある場合、どのようにしてそれらを再び戻すのですか?できれば、selectステートメントなどを使用していますか?
これが私がこれまでに得たものです:
declare
type array is table of number index by binary_integer;
pidms array;
begin
for i in (
select distinct sgbstdn_pidm
from sgbstdn
where sgbstdn_majr_code_1 = 'HS04'
and sgbstdn_program_1 = 'HSCOMPH'
)
loop
pidms(pidms.count+1) := i.sgbstdn_pidm;
end loop;
select *
from pidms; --Oracle DOESN'T LIKE THIS BIT!!!
end;
Dbms_output.putline()を使用してそれらを出力できることはわかっていますが、他のテーブルから選択するのと同じように結果セットを取得したいと思っています。
事前にありがとう、マット
グローバル一時テーブルが必要になる場合があります。
Oracleでは、これらは一度作成され、呼び出されると、データはセッションに対して非公開になります。
このようなものを試してください...
CREATE GLOBAL TEMPORARY TABLE temp_number
( number_column NUMBER( 10, 0 )
)
ON COMMIT DELETE ROWS;
BEGIN
INSERT INTO temp_number
( number_column )
( select distinct sgbstdn_pidm
from sgbstdn
where sgbstdn_majr_code_1 = 'HS04'
and sgbstdn_program_1 = 'HSCOMPH'
);
FOR pidms_rec IN ( SELECT number_column FROM temp_number )
LOOP
-- Do something here
NULL;
END LOOP;
END;
/
Oracleでは、PL/SQLエンジンとSQLエンジンはある程度の分離を維持しています。 PL/SQL内でSQLステートメントを実行すると、SQLステートメントはSQLエンジンに渡されます。SQLエンジンは、INDEX BYテーブルなどのPL/SQL固有の構造を認識していません。
したがって、PL/SQLブロックで型を宣言する代わりに、データベーススキーマ内に同等のコレクション型を作成する必要があります。
CREATE OR REPLACE TYPE array is table of number;
/
次に、PL/SQL内で次の2つの例のように使用できます。
SQL> l
1 declare
2 p array := array();
3 begin
4 for i in (select level from dual connect by level < 10) loop
5 p.extend;
6 p(p.count) := i.level;
7 end loop;
8 for x in (select column_value from table(cast(p as array))) loop
9 dbms_output.put_line(x.column_value);
10 end loop;
11* end;
SQL> /
1
2
3
4
5
6
7
8
9
PL/SQL procedure successfully completed.
SQL> l
1 declare
2 p array := array();
3 begin
4 select level bulk collect into p from dual connect by level < 10;
5 for x in (select column_value from table(cast(p as array))) loop
6 dbms_output.put_line(x.column_value);
7 end loop;
8* end;
SQL> /
1
2
3
4
5
6
7
8
9
PL/SQL procedure successfully completed.
コメントに基づく追加の例
私の回答と質問自体に対するあなたのコメントに基づいて、私はこれが私がそれを実装する方法だと思います。パッケージを使用して、レコードを実際のテーブルから一度フェッチし、プライベートパッケージグローバルに格納できるようにします。開いている参照カーソルを返す関数があります。
CREATE OR REPLACE PACKAGE p_cache AS
FUNCTION get_p_cursor RETURN sys_refcursor;
END p_cache;
/
CREATE OR REPLACE PACKAGE BODY p_cache AS
cache_array array;
FUNCTION get_p_cursor RETURN sys_refcursor IS
pCursor sys_refcursor;
BEGIN
OPEN pCursor FOR SELECT * from TABLE(CAST(cache_array AS array));
RETURN pCursor;
END get_p_cursor;
-- Package initialization runs once in each session that references the package
BEGIN
SELECT level BULK COLLECT INTO cache_array FROM dual CONNECT BY LEVEL < 10;
END p_cache;
/
SQL配列タイプは必要ありません。エレメントタイプがプリミティブタイプの場合は除きます。 (バーチャー、数値、日付、...)
非常に基本的なサンプル:
declare
type TPidmList is table of sgbstdn.sgbstdn_pidm%type;
pidms TPidmList;
begin
select distinct sgbstdn_pidm
bulk collect into pidms
from sgbstdn
where sgbstdn_majr_code_1 = 'HS04'
and sgbstdn_program_1 = 'HSCOMPH';
-- do something with pidms
open :someCursor for
select value(t) pidm
from table(pidms) t;
end;
それを再利用したい場合、それがどのように見えるかを知るのは興味深いかもしれません。複数のコマンドを発行すると、それらがパッケージにグループ化される可能性があります。上からのプライベートパッケージ変数のトリックには欠点があります。変数をパッケージに追加すると、パッケージに状態が与えられ、ステートレスな機能の束としてではなく、奇妙な種類のシングルトンオブジェクトインスタンスとして機能します。
例えば本体を再コンパイルすると、それを以前に使用したセッションで例外が発生します。 (変数値が無効になったため)
ただし、パッケージで(またはSQLでグローバルに)型を宣言し、それを使用する必要があるメソッドでパラメーターとして使用することもできます。
create package Abc as
type TPidmList is table of sgbstdn.sgbstdn_pidm%type;
function CreateList(majorCode in Varchar,
program in Varchar) return TPidmList;
function Test1(list in TPidmList) return PLS_Integer;
-- "in" to make it immutable so that PL/SQL can pass a pointer instead of a copy
procedure Test2(list in TPidmList);
end;
create package body Abc as
function CreateList(majorCode in Varchar,
program in Varchar) return TPidmList is
result TPidmList;
begin
select distinct sgbstdn_pidm
bulk collect into result
from sgbstdn
where sgbstdn_majr_code_1 = majorCode
and sgbstdn_program_1 = program;
return result;
end;
function Test1(list in TPidmList) return PLS_Integer is
result PLS_Integer := 0;
begin
if list is null or list.Count = 0 then
return result;
end if;
for i in list.First .. list.Last loop
if ... then
result := result + list(i);
end if;
end loop;
end;
procedure Test2(list in TPidmList) as
begin
...
end;
return result;
end;
それを呼び出す方法:
declare
pidms constant Abc.TPidmList := Abc.CreateList('HS04', 'HSCOMPH');
xyz PLS_Integer;
begin
Abc.Test2(pidms);
xyz := Abc.Test1(pidms);
...
open :someCursor for
select value(t) as Pidm,
xyz as SomeValue
from table(pidms) t;
end;