- PR -

[Ora10] 配列を返すパッケージを SQL*Plus からテストする方法

1
投稿者投稿内容
こばさん
大ベテラン
会議室デビュー日: 2004/03/17
投稿数: 147
投稿日時: 2008-07-07 21:43
 これまでは SQL Server ばかりやってきたのですが、ここに来て Oracle のストアド/パッケージを触らないといけない羽目になりました。
 配列(パッケージで定義された表というべきか?)を返すパッケージ(プロシージャ)を作ったのですが、SQL*Plus からテストする方法が分かりません。
 検索するも、あまりに漠然としすぎているせいか、なかなか見つけれることが出来ず・・・


CREATE OR REPLACE PACKAGE KOBA
IS
   TYPE TYP_DAY IS RECORD (
     日付 NUMBER(8,0),
     区分 NUMBER(1,0)
   );
   TYPE TYP_DAYS IS TABLE OF TYP_DAY INDEX BY BINARY_INTEGER;

   PROCEDURE TEST(OT_CURSOR OUT TYP_DAYS);
END;
/

CREATE OR REPLACE PACKAGE BODY KOBA
IS
  PROCEDURE TEST(OT_CURSOR OUT TYP_DAYS)
  IS
    REC_DAYS TYP_DAYS;
  BEGIN
    REC_DAYS(0).日付 := 20080701;
    REC_DAYS(0).区分 := 0;
    REC_DAYS(1).日付 := 20080702;
    REC_DAYS(1).区分 := 1;
    OT_CURSOR := REC_DAYS;
  END;
END;
/


 こんなパッケージです。
 SQL*Plus から、このパッケージを実行して、日付・区分を列とする表が正しく生成されているかを見たいのですが・・・
 今日一日で Function → Procedure → Package と「何が出来て何が出来ないのか?」を勉強していって、ここで挫折しました。

 実表があれば SYS_REFCURSOR 使った Procedure で(Package作らずとも)出来そうに思いましたが、手動で表を作る場合は Package を作らないといけないのかな?という理解でおります。SYS_REFCURSOR が返値であれば SQL*Plus 上から
  var v refcursor;
  exec koba.test(:v);
  print;
ていう感じで確かめられたのですが、同じような手法が通用せず・・・

 お手数をおかけしますが、どうぞよろしくお願い致します。
99ri
大ベテラン
会議室デビュー日: 2006/09/09
投稿数: 129
投稿日時: 2008-07-07 22:49
dbms_output.put_lineプロシージャで変数の内容をsqlplusに出力できます
表示するためには、SQL*Plusで下記を実行する必要があります
set serveroutput on

declareからend;までのコードがサーバに送られ実行されます

set serveroutput on;
declare
out KOBA.TYP_DAYS ;
begin
KOBA.test(out);
dbms_output.put_line(out(0).ymd);
dbms_output.put_line(out(0).kbn);
dbms_output.put_line(out(1).ymd);
dbms_output.put_line(out(1).kbn);
end;
/

PL/SQLパッケージ・プロシージャおよびタイプ・リファレンス
http://otndnld.oracle.co.jp/document/products/oracle10g/102/doc_cd/appdev.102/B19245-02/toc.htm

逆に質問しますがSQLServerの場合はどういうコードになるのでしょうか?

[ メッセージ編集済み 編集者: 99ri 編集日時 2008-07-08 00:56 ]
こばさん
大ベテラン
会議室デビュー日: 2004/03/17
投稿数: 147
投稿日時: 2008-07-09 16:46
 ありがとうございました!
 うまくテストできました。

 SQL Server ですが、Oracle のような配列という概念はない(私がないと思ってるだけかもしれませんが)ので、私の場合は、ストアドの中で一時テーブルを作ってそれを戻すようにしてます。

 Oracle の場合、SQL Server ライクな一時テーブルというものが存在しないと思い、(私が見つけていないだけかもしれませんが)、色々とネットで探して今回のような配列を返すようにしました。
→create global temporary table 〜は少し使い方に癖がある気がしまして・・
こばさん
大ベテラン
会議室デビュー日: 2004/03/17
投稿数: 147
投稿日時: 2008-08-01 19:50
 少し前のスレッドですが、続きの話ですみません。

 オラクル側のプログラミング(とSQL*Plusからテスト)が済んで、次は VB.NET から呼び出す側を作るフェーズに入りました。

 それほど難しくないだろうとタカを括っていたのですが、この手のいわゆる「PL/SQL表」の取得方法が分かりません。
 REF_CURSOR を返すもの、および PL/SQL表のうち一次元配列を返すもの、についてはそれぞれ解決策が分かったのですが、今回のような二次元配列(列と行を持った配列)の取得方法が分かりません。

 OracleParameter の使い方の周辺だけで結構なので、突破口だけでも何か手がかりを御教示いただけないでしょうか。

 ちなみに、PL/SQL表でない、普通の変数を入出力引数に持つパッケージの呼び出しや値の取得は出来てます。
(そこまでは理解できているるスキルレベルです)
dodo
ベテラン
会議室デビュー日: 2004/05/12
投稿数: 99
お住まい・勤務地: 東京都渋谷区
投稿日時: 2008-08-01 22:06
引用:
こばさんさんの書き込み (2008-08-01 19:50) より:

今回のような二次元配列(列と行を持った配列)の取得方法が分かりません。
 OracleParameter の使い方の周辺だけで結構なので、突破口だけでも何か手がかりを御教示いただけないでしょうか。



"pl sql表 VB.NET"で検索すると、@ITのこの記事が最初に出てきますが、参考になりますでしょうか?
http://www.atmarkit.co.jp/fdb/rensai/odpdotnet03/odpdotnet03_3.html
こばさん
大ベテラン
会議室デビュー日: 2004/03/17
投稿数: 147
投稿日時: 2008-08-04 12:48
 御回答ありがとうございます。
 やはり、そういう風に一次元配列を使った複数の引数に分割、という風にしないといけないのでしょうか。
99ri
大ベテラン
会議室デビュー日: 2006/09/09
投稿数: 129
投稿日時: 2008-08-04 23:05
表関数をしようすることで可能と思います
またPIPELINED句指定でSELECTと同じ方式で扱えます

■参考URL
otndnld.oracle.co.jp/document/products/oracle10g/102/doc_cd/index.htm
Oracle Database アプリケーション開発者ガイド-基礎編
10gリリース2(10.2)
 ファンクションからの大量のデータの戻し

Oracle Database PL/SQLユーザーズ・ガイドおよびリファレンス
10g リリース2(10.2)
 5 PL/SQLのコレクションおよびレコードの使用

Oracle Database SQLリファレンス
 CREATE FUNCTION

■検索キー
 oracle 表関数 PIPELINED

■コール側
PIPELINED句指定の表関数は表をSELECTする形式でSQLを記述できる
SQL> select * from table(KOBA.FTEST);

ODP.Net
OracleCommand cmd = new OracleCommand("select * from table(KOBA.FTEST)", oracleconnection);
OracleDataReader reader = cmd.ExecuteReader();

■パッケージ側
コード:

CREATE OR REPLACE PACKAGE KOBA
----RECORDの結合配列(索引付き表)は
----PL/SQLでは処理できないためネストした表に変更
TYPE TYP_DAYARY IS TABLE OF TYP_DAY ;

----コレンクション型(ネストした表またはVARRAY)を戻す
FUNCTION FTEST RETURN TYP_DAYARY PIPELINED;
END;

CREATE OR REPLACE PACKAGE BODY KOBA
IS
FUNCTION FTEST RETURN TYP_DAYARY PIPELINED
IS
REC_DAYS TYP_DAYARY;
BEGIN
----ネストシタ表ノ初期化 要素数5
REC_DAYS := TYP_DAYARY(null,null,null,null,null);

REC_DAYS(1).日付 := 20080701;
REC_DAYS(1).区分 := 0;
PIPE ROW(REC_DAYS(1));

REC_DAYS(2).日付 := 20080702;
REC_DAYS(2).区分 := 1;
PIPE ROW(REC_DAYS(2));
----
RETURN;
END;
END;



コード:

----既存のPROCEDUREコールをラップ
----コールインターフェースはパイプライン表関数
FUNCTION FTEST2
return TYP_DAYARY
PIPELINED
is
out_recs TYP_DAYARY;
REC_DAYS TYP_DAYS;
BEGIN
out_recs :=TYP_DAYARY();

TEST(REC_DAYS);

for i in REC_DAYS.First .. REC_DAYS.LAST loop
out_recs.EXTEND;
out_recs(i+1) := REC_DAYS(i);
pipe ROW(out_recs(i+1));
end loop;
return ;
end;



[ メッセージ編集済み 編集者: 99ri 編集日時 2008-08-05 20:58 ]
こばさん
大ベテラン
会議室デビュー日: 2004/03/17
投稿数: 147
投稿日時: 2008-08-07 15:14
 どうもありがとうございます。
 そういう方法があるんですか。

 だけど FUNCTION にすると戻り値が一つしか持てない。。
(テーブル型の中に含めてしまえばよいのかもしれないが)

 すごく勉強になりました。とても感謝してます。
1

スキルアップ/キャリアアップ(JOB@IT)