PL/SQLのプロシージャでカーソルの受渡について

このQ&Aのポイント
  • PL/SQLのプロシージャ間でカーソルの受渡について教えてください。
  • VBでの例を交えながら、親と子プロシージャ間でカーソルを受け渡す方法について教えてください。
  • カーソルを子プロシージャで生成し、親プロシージャに戻すことは可能なのでしょうか?
回答を見る
  • ベストアンサー

PL/SQLのプロシージャ間でカーソル?の受渡

PL/SQLのプロシージャ間でカーソル?の受渡 お世話になります。 親でループ対象とするカーソルを、子プロシージャで生成し 親に戻すということは可能でしょうか。 うまく伝わりにくいかと思いますので、下記にVBで行った例を記します。 親----------------------- Sub aaa()   Dim rs As New ADODB.Recordset    Call bbb(rs)    Do Until rs.EOF      Debug.Print rs!COLUMN1      rs.MoveNext    Loop End Sub 子----------------------- Function bbb(ByRef rs As ADODB.Recordset)  rs.Open "SELECT * FROM TABLE1", CurrentProject.Connection End Function 以上、お願い致します。

質問者が選んだベストアンサー

  • ベストアンサー
  • yamada_g
  • ベストアンサー率68% (258/374)
回答No.2

エラーの原因は、カーソル変数の場合はforループを利用できないためだと思います。 なので、loop内fetchするようにします。 こんな感じでしょうか --REF CUSOR宣言 CREATE OR REPLACE PACKAGE PKG_TEST_CURSOR IS --TYPE CUR_TEST IS REF CURSOR; --レコード全体を取得するなら型を指定した方が楽だと思います TYPE CUR_TEST IS REF CURSOR RETURN TEST%ROWTYPE; END; / --親プロシージャ CREATE OR REPLACE PROCEDURE PC_TEST親(PI_HIKISU1 IN TEST.TEST_COLUMN%TYPE) IS  TEST_REC PKG_TEST_CURSOR.CUR_TEST; -- l_test_rec PKG_TEST_CURSOR.CUR_TEST;  --CUR_TEST を型指定したのでrowtypeが使えます  l_test_rec TEST_REC%ROWTYPE; BEGIN  PD_TEST子(PI_HIKISU1,TEST_REC); -- FOR l_test_rec IN TEST_REC LOOP --  dbms_output.put_line(l_test_rec.TEST_COLUMN99); -- END LOOP;  --ref cursorの場合はforループはできないので  loop   fetch TEST_REC into l_test_Rec;   exit when TEST_REC%notfound;   dbms_output.put_line(l_test_rec.TEST_COLUMN99);  end loop;  close TEST_REC; END; / --子プロシージャ CREATE OR REPLACE PROCEDURE PD_TEST子  (   PI_HIKISU1 IN TEST.TEST_COLUMN%TYPE,   PI_TEST_RECIN OUT PKG_TEST_CURSOR.CUR_TEST) IS  l_test_rec PKG_TEST_CURSOR.CUR_TEST; BEGIN  OPEN l_test_rec FOR SELECT * FROM TEST WHERE TEST_COLUMN = PI_HIKISU1;  --カーソルを返すならopenするだけでいいのでは? -- LOOP --  EXIT WHEN l_test_rec%NOTFOUND; --    FETCH lc_test_rec INTO PI_TEST_REC; --  END LOOP; END; /

forgedcode
質問者

お礼

yamada_g 様 細かく教えて頂きありがとうございました。 無事に動作する事を確認できました。 ただ一部誤りがあるようでした。 --子プロシージャ CREATE OR REPLACE PROCEDURE PD_TEST子  (   PI_HIKISU1 IN TEST.TEST_COLUMN%TYPE,   PI_TEST_RECIN OUT PKG_TEST_CURSOR.CUR_TEST) IS  --l_test_rec PKG_TEST_CURSOR.CUR_TEST;--←直接引数に返すので必要ない BEGIN  --OPEN l_test_rec FOR SELECT * FROM TEST WHERE TEST_COLUMN = PI_HIKISU1;  OPEN PI_TEST_REC FOR SELECT * FROM TEST WHERE TEST_COLUMN = PI_HIKISU1; --←引数に返してあげる 以上です、本当に助かりました。

その他の回答 (1)

  • yamada_g
  • ベストアンサー率68% (258/374)
回答No.1
forgedcode
質問者

補足

yamada_g様 ご回答ありがとうございます。 教えて頂いたとおりref cursorでいけそうですが 実際コーディングしたところ、うまくいきませんでした。 どこか考え方が根本的に間違ってるかもしれません。 エラーは親プロシージャで [TEST_RECがプロシージャではないか、未定義です」と出ます。 ご指摘いただければ幸いです。 --REF CUSOR宣言 CREATE OR REPLACE PACKAGE PKG_TEST_CURSOR IS TYPE CUR_TEST IS REF CURSOR; END; --親プロシージャ CREATE OR REPLACE PROCEDURE PC_TEST親(PI_HIKISU1 IN TEST.TEST_COLUMN%TYPE) IS  TEST_REC PKG_TEST_CURSOR.CUR_TEST;  l_test_rec PKG_TEST_CURSOR.CUR_TEST; BEGIN  PD_TEST子(PI_HIKISU1,TEST_REC);  FOR l_test_rec IN TEST_REC LOOP   dbms_output.put_line(l_test_rec.TEST_COLUMN99);  END LOOP; END; --子プロシージャ CREATE OR REPLACE PROCEDURE PD_TEST子  (   PI_HIKISU1 IN TEST.TEST_COLUMN%TYPE,   PI_TEST_REC IN OUT PKG_TEST_CURSOR.CUR_TEST) IS  l_test_rec PKG_TEST_CURSOR.CUR_TEST; BEGIN  OPEN l_test_rec FOR SELECT * FROM TEST WHERE TEST_COLUMN = PI_HIKISU1;  LOOP   EXIT WHEN l_test_rec%NOTFOUND;     FETCH lc_test_rec INTO PI_TEST_REC;   END LOOP; END;

関連するQ&A

  • ADOでレコードを閉じるタイミング。。Access2000/VB6/Win2K

    レコードセットを返すFuncitonプロシージャーを作ってみたのですが。。。 下のGet_Recordsの方のレコードセットをCloseすると上の方のDisp_Dataでオブ ジェクトが閉じているといって怒られます。しかし、閉じないと下の方では開きっ ぱなしになると思うのですが。。。どのように処理すればいいのでしょうか? Public P_CN As ADODB.Connection Private Sub Disp_Date()   Dim RS As ADODB.Recordset   Dim SQL AS String    Set RS = Get_Records(SQL)     With RS      If .RecordCount > 0 Then       .MoveLast: .MoveFirst       .Debug.Print !顧客_ID        End If      End With      RS.Close     Set RS = Nothing End Sub Public Function Get_Records(pSQL As String) As ADODB.Recordset   Dim RS As ADODB.Recordset     Set RS = New ADODB.Recordset      RS.Open pSQL, P_CN, adOpenKeyset, adLockOptimistic     Set Get_Records = RS '''    RS.Close '''   Set RS = Nothing End Function

  • VB6の複数検索条件で連続検索が出来ないので教えて下さい

    下記のごとく、ADOデーターベースの複数アンド条件で検索をしているのですが、一番最初のレコードは検索されるのですが、次の検索をしようと思い、rs.movenextを実行しても次のレコードに飛んで検索をしてくれません。たった一度のみの検索となります。 連続検索を行いたいのですが分かりません。 どなたか、詳しい方がおられましたら宜しくお願い致します。 Public Sub Multi_find(ByRef oRs As ADODB.Recordset, sCriteria As String) Dim clone_rs As ADODB.Recordset Set clone_rs = oRs.Clone clone_rs.Filter = sCriteria If clone_rs.EOF Or clone_rs.BOF Then oRs.MoveLast oRs.MoveNext Else oRs.Bookmark = clone_rs.Bookmark End If clone_rs.Close Set clone_rs = Nothing End Sub

  • rs.MoveFirst

    アクセスvbaです。 Sub Sample() Dim cn As New ADODB.Connection Dim rs As New ADODB.Recordset Dim i As Long Set cn = CurrentProject.Connection rs.Open "Tテーブル", cn, adOpenKeyset, adLockOptimistic rs.MoveFirst '←これいらない? For i = 1 To rs.RecordCount rs.MoveNext Next rs.Close: Set rs = Nothing cn.Close: Set cn = Nothing End Sub このようなコードの場合 rs.MoveFirst はあってもなくても変わらないですか?

  • 引数付のFuncitonプロシージャと引数付のSUBプロシージャの違い

    親プロシージャに数値を渡すときに、引数付のFuncitonプロシージャと引数付のSUBプロシージャは、結果を見ると同じ動きをするように思います。 このような場合、両者には、どのような違いがあるのでしょうか? Sub 親プロシージャ() Cells(1,MyNOend)=123 end Sub ・子プロシージャ Function FMyRowCnt(MyNOend As Integer) MyNOend = TMYKanriBkWs1.Range("D1").CurrentRegion.Rows.Count End Function Sub FMyRowCnt(MyNOend As Integer) MyNOend = TMYKanriBkWs1.Range("D1").CurrentRegion.Rows.Count End Sub 以上 よろしくお願い致します。

  • ADO 「Set」は使ったほうがいいのでしょうか?

    Sub test1() Dim cn As ADODB.Connection Dim rs As ADODB.Recordset Set cn = New ADODB.Connection Set rs = New ADODB.Recordse End Sub Sub test2() Dim cn As New ADODB.Connection Dim rs As New ADODB.Recordset End Sub この二つは同じ意味ですか? 「Set」は使ったほうがいいのでしょうか? よろしくお願いします。

  • SQL文の最後に「;」はいらないのでしょうか?

    VBAのADOについて質問です。 SQL文の最後には「;」を付けなくちゃいけないものだと思っているのですが ・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・ Private Sub test_Click() Dim CN As ADODB.Connection Dim RS As ADODB.Recordset Set CN = CurrentProject.Connection Set RS = New ADODB.Recordset SQL = "SELECT * FROM Tテーブル" ・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・ でも問題なくコードが動きました。 SQL文の最後に「;」はいらないのでしょうか? ちなみに SQL = "SELECT * FROM Tテーブル;" でもエラーになりませんでした。

  • ADO オブジェクトの渡し方

    こんにちは。ADOについてお教えください。 フォームをロード時に接続プロシージャと切断プロシージャを走らせたいと思います。 ConnectDatabaseを呼び出しは成功しますが、CloseDatabase呼び出しには失敗します。 スコープの問題で、rs、cnのオブジェクトが無い為だと思います。 ConnectDatabaseで作成されたcn、rsオブジェクトを別の関数で処理するにはどのようにコードをかけばよろしいでしょうか?宜しくお願い致します。 Private Sub Form_Load() Call ConnectDatabase Call CloseDatabase End Sub Module1 ------------------ sub ConnectDatabase() Dim cn As ADODB.Connection Dim rs As ADODB.Recordset Set cn = New ADODB.Connection Set rs = New ADODB.Recordset 処理~~~~ end sub sub CloseDatabase() rs.Close cn.Close Set rs = Nothing Set cn = Nothing end sub

  • ACCESS SQLで複数データ表示させるには?

    *************************************************** Private Sub Form_Load() Dim cn As New ADODB.Connection Dim rs As New ADODB.Recordset Set cn = CurrentProject.Connection mySQL = "select * from テーブル" rs.Open mySQL, cn, adOpenForwardOnly, adLockOptimistic ’コントロールに代入 Me.No = rs![No] Me.項目 = rs![項目] ・・・ End Sub *************************************************** こんな感じで、クエリでなくSQLで フォームにテーブルの全レコードを表示させたい場合、 どのようにすればよいのでしょうか? 上の文には、何が不足しているのでしょうか? http://www.accessclub.jp/ado/09.html を見ましたが、解決できませんでした。

  • Functionプロシージャの便利さがわかりません

    私はVBAコードを作る時は、もっぱらsubプロシージャーを使ってしまうのですが、 http://excelvba.pc-users.net/fol5/5_4.html を参考に、 Functionプロシージャとsubプロシージャの違いを確認してみたのですが、 Functionプロシージャの便利さがわかりません。 *********************************** Sub Test() SubプロシージャとFunctionプロシージャのテスト i = 1 Call Subプロシージャ(i) i = Functionプロシージャ(i) MsgBox "Functionプロシージャ結果:" + CStr(i) End Sub Sub Subプロシージャ(ByVal i As Integer) MsgBox "Subプロシージャ結果:" + CStr(i) End Sub Function Functionプロシージャ(ByVal i As Integer) As Integer i = i + 1 Functionプロシージャ = i End Function *********************************** Functionプロシージャは、 (ByVal i As Integer) As Integer のように、、二回もデータ型(Integer)の指定をしなくてはいけないのでしょうか? リンク先の説明には、 「SubプロシージャとFunctionプロシージャの違いは Subプロシージャが引数を受け取るのみに対して Functionプロシージャは引数を受け取り、 戻り値を返すという関数としての役割を果たすことができる点です。」 と記載されてますが、 それはSubプロシージャでも出来てますよね? サンプルコードにおいてのFunctionプロシージャの便利さを教えてください。

  • PL/SQL-プロシージャ

    プロシージャBはテスト実行のため、プロシージャAを真似て作成しています。 --最後のIF文で、プロシージャAかBのどちらかに走らせたいと思っています。 DECLARE --プロシージャA--------------------------------------- PROCEDURE A IS fno1 utl_file.file_type; dnm1 varchar(200) :='XXX'; fnm1 varchar2(200) :='BBB.txt'; CURSOR cu1 is select XYZ as ABC from CCC; BEGIN fno1 := utl_file.fopen(dnm1,fnm1,'w'); FOR CU1_REC1 in CU1 loop utl_file_put_line(fno1,' '|| CU1_REC1.XYZ END LOOP; utl_file.fclose(fno1); end; --プロシージャB------------------------------------- プロシージャAと似たような処理 --プロシージャAかBかを判定するIF文------------------------------ BEGIN IF CCC.ABC = '0'; THEN A; ELSE B; ENDIF; END; /

専門家に質問してみよう