PL/SQLをOracle19で使ってみた

ストアドプロシージャーでDB処理

仕事先で偶然にかち合いました。ストアドプロシージャー。

プログラムのリプレース(古いプログラムの機能を新しく書き直したプログラムで置き換えること)作業で、参画時のブリーフィングで使っていると聞きましたが、私はPL/SQLに触れるのははじめてです。

せっかく仕事で触れる機会があったのだから、自分のスキルにしてしまおうという魂胆です(w)

PL/SQL開発の準備

まずは、PL/SQLが実装できる環境を用意しましょう。

Oracleの実行環境

今回は、以前にインストール関係の記事を書いたOracleの環境が残っていたため、それをそのまま使用します。

インストールと環境設定

このとき、サンプルスキーマとして、HRもインストールしましたので、それを使用して作成していきます。

Oracleデータベース起動

インストールは完了していますので、Oracleデータベースを起動します。

sqlplus / as sysdba で、sysdbaユーザーでログインし、起動コマンドを入力するのですが……

[oracle@oracledb ~]$ sqlplus / as sysdba

SQL*Plus: Release 19.0.0.0.0 - Production on Wed Jun 29 17:05:21 2022
Version 19.3.0.0.0

Copyright (c) 1982, 2019, Oracle.  All rights reserved.

Connected to an idle instance.

SQL> STARTUP
ORACLE instance started.

Total System Global Area 2415917880 bytes
Fixed Size		    8899384 bytes
Variable Size		  553648128 bytes
Database Buffers	 1845493760 bytes
Redo Buffers		    7876608 bytes
?????????????????
?????????????????
SQL> 

ん?文字化けしますね。

oracle Linux oracle sqlplus linux 文字化け でGoogle検索したところ、こちらのサイト様がヒットしました。

こちらの記事どおり、vi .bash_profile でファイルを開き、export NLS_LANG=Japanese_Japan.AL32UTF8 を追記して再起動したら……

[oracle@oracledb ~]$ sqlplus / as sysdba

SQL*Plus: Release 19.0.0.0.0 - Production on 水 6月 29 17:15:09 2022
Version 19.3.0.0.0

Copyright (c) 1982, 2019, Oracle.  All rights reserved.

アイドル・インスタンスに接続しました。

SQL> STARTUP
ORACLEインスタンスが起動しました。

Total System Global Area 2415917880 bytes
Fixed Size		    8899384 bytes
Variable Size		  553648128 bytes
Database Buffers	 1845493760 bytes
Redo Buffers		    7876608 bytes
データベースがマウントされました。
データベースがオープンされました。
SQL> 

いや本当に待ってくださいよ。CentOSにOracle12cをインストールしたときのお話ですよ?これ。

こちらのはOracle Linuxなんですよ? それにOracle19.3をインストールしているっていうのに、日本語処理すら解決できてなくて、ユーザーに記述変更させるんですか?

気を取り直し、リスナーも繋ぎます。

$ lsnrctl start

LSNRCTL for Linux: Version 19.0.0.0.0 - Production on 29-6月 -2022 17:25:51

Copyright (c) 1991, 2019, Oracle.  All rights reserved.

/u01/app/oracle/product/19.3.0/dbhome_1/bin/tnslsnrを起動しています。お待ちください...

TNSLSNR for Linux: Version 19.0.0.0.0 - Production
システム・パラメータ・ファイルは/u01/app/oracle/product/19.3.0/dbhome_1/network/admin/listener.oraです。
ログ・メッセージを/u01/app/oracle/diag/tnslsnr/oracledb/listener/alert/log.xmlに書き込みました。
リスニングしています: (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=oracledb)(PORT=1521)))
リスニングしています: (DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC1521)))

(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=oracledb)(PORT=1521)))に接続中
リスナーのステータス
------------------------
別名                      LISTENER
バージョン                TNSLSNR for Linux: Version 19.0.0.0.0 - Production
開始日                    29-6月 -2022 17:25:52
稼働時間                  0 日 0 時間 0 分 0 秒
トレース・レベル          off
セキュリティ              ON: Local OS Authentication
SNMP                      OFF
パラメータ・ファイル      /u01/app/oracle/product/19.3.0/dbhome_1/network/admin/listener.ora
ログ・ファイル            /u01/app/oracle/diag/tnslsnr/oracledb/listener/alert/log.xml
リスニング・エンドポイントのサマリー...
  (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=oracledb)(PORT=1521)))
  (DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC1521)))
リスナーはサービスをサポートしていません。
コマンドは正常に終了しました。

続いて、sqlplusでサンプルスキーマのHRにログインしてみます。

$ sqlplus HR/HR

SQL*Plus: Release 19.0.0.0.0 - Production on 水 6月 29 17:28:00 2022
Version 19.3.0.0.0

Copyright (c) 1982, 2019, Oracle.  All rights reserved.

最終正常ログイン時間: 火 6月  28 2022 13:23:42 +09:00


Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.3.0.0.0
に接続されました。
SQL> 

いろいろ思うところはありますが、とりあえずOracleデータベースを起動し、sqlplusの起動環境までは確保できました。

参考

少し古い本ですが、こちらを参考にしました。

本の環境は、Oracle12cでの実行を前提としていまして、インストールについても書かれていますが、現状、Oracle12cを入手する事は難しいので、19cで行う事にします。

また、書籍ではWindows環境でのプログラム作成などを前庭としてますが、実行はこのとき構築したOracle Linux 上で行う事とします。

最初の一歩/HelloWorld

プログラムの勉強は、まずは何はなくともHelloWorldと表示してみるところから始まります。

PL/SQLはSQLですが、手続き型プログラム言語であるため、HelloWorldを表示するプログラムが書けます。

参考にした「基礎からわかる PL/SQL」から、最初のPL/SQLを記述してみます。

SQL> SET SERVEROUTPUT ON
SQL> BEGIN
  2   DBMS_OUTPUT.PUT_LINE('HELLO WORLD');
  3  END;
  4  /
HELLO WORLD

PL/SQLプロシージャが正常に完了しました。

SQL> 

最初のSET SERVEROUTPUT ON は、sqlplusでログインしたとき、一回実行すればOKとの事です。

DBMS_OUTPUT.PUT_LINE が、PL/SQLでは標準出力に出力するコマンドで、正常にHELLO WORLDが出力されました。

ファイルから実行する

最初のPL/SQLは、sqlplusの画面に直接記述しました。

しかし、ソースコードとして何処かに記述しておかないと、ミスしたときの修正や、改良ができませんので、このプログラムのソースコードとして保存し、実行してみる事にします。

SET ECHO ON
BEGIN
 DBMS_OUTPUT.PUT_LINE('HELLO WORLD2');
 END;
 /

これをSQLファイルとして、適当なディレクトリに保存します。

今回は、実行環境にoracleユーザーがいますので、そのホームディレクトリの直下に、plsqlというディレクトリを作成しました。

そこにLIST2-4.SQL の名前で上記の内容を保存します。

実行は、

SQL> START /home/oracle/plsql/LIST2-4.SQL
SQL> BEGIN
  2   DBMS_OUTPUT.PUT_LINE('HELLO WORLD2');
  3   END;
  4   /
HELLO WORLD2

PL/SQLプロシージャが正常に完了しました。

SQL> 

で正常に実行できました。

データを取得する

今回、使用しているのは、Oracleデータベースのサンプルスキーマ HRです。

なので、SELECTでデータが取得できます。

 SELECT * FROM EMPLOYEES;

EMPLOYEE_ID FIRST_NAME		 LAST_NAME
----------- -------------------- -------------------------
EMAIL			  PHONE_NUMBER	       HIRE_DAT JOB_ID	       SALARY
------------------------- -------------------- -------- ---------- ----------
COMMISSION_PCT MANAGER_ID DEPARTMENT_ID
-------------- ---------- -------------
	100 Steven		 King
SKING			  515.123.4567	       03-06-17 AD_PRES 	24000
				     90

	101 Neena		 Kochhar
NKOCHHAR		  515.123.4568	       05-09-21 AD_VP		17000
		      100	     90

EMPLOYEE_ID FIRST_NAME		 LAST_NAME
----------- -------------------- -------------------------
EMAIL			  PHONE_NUMBER	       HIRE_DAT JOB_ID	       SALARY
------------------------- -------------------- -------- ---------- ----------
COMMISSION_PCT MANAGER_ID DEPARTMENT_ID
-------------- ---------- -------------

	102 Lex 		 De Haan
LDEHAAN 		  515.123.4569	       01-01-13 AD_VP		17000
		      100	     90

	103 Alexander		 Hunold
AHUNOLD 		  590.423.4567	       06-01-03 IT_PROG 	 9000

EMPLOYEE_ID FIRST_NAME		 LAST_NAME
----------- -------------------- -------------------------
~中略~

107行が選択されました。

しかし、PL/SQL上では、SELECTでデータを取得できません。

試しに、上記のSELECT文を発行してみます。

SET ECHO ON
BEGIN
   SELECT * FROM EMPLOYEES;
END;
/

を5-1.SQLというファイルにして実行すると

SQL> START /home/oracle/plsql/5-1.SQL
SQL> SET ECHO ON
SQL> BEGIN
  2  	SELECT * FROM EMPLOYEES;
  3  END;
  4  /
   SELECT * FROM EMPLOYEES;
   *
行2でエラーが発生しました。:
ORA-06550: 行2、列4:
PLS-00428: INTO句はこのSELECT文に入ります。

SQL> 

とエラーになります。

これはPL/SQL上ではSELECTは直接実行できず、SELECT INFO を使用するためです。

また、他のプログラムでもそうですが、実行した結果をどこにどのように戻すのかは必須の記述になりますが、これには記載されていません。

SELECT INFOを使用し、戻り値は変数に格納して、PUT_LINEで表記する事になります。

SET ECHO ON
DECLARE
	v_department_id EMPLOYEES.DEPARTMENT_ID%TYPE;
	v_first_name EMPLOYEES.FIRST_NAME%TYPE;
	v_last_name EMPLOYEES.LAST_NAME%TYPE;
BEGIN
	SELECT DEPARTMENT_ID,FIRST_NAME,LAST_NAME
	 INTO v_department_id,v_first_name,v_last_name
	 FROM EMPLOYEES
	 WHERE EMPLOYEE_ID =100;

	DBMS_OUTPUT.PUT_LINE('ID:'||v_department_id);
	DBMS_OUTPUT.PUT_LINE('NAME:'||v_first_name || ' ' ||v_last_name);
END;
/

これを、5-3.SQLというファイルにして実行すると

SQL> START /home/oracle/plsql/5-3.SQL
SQL> SET ECHO ON
SQL> DECLARE
  2  	     v_department_id EMPLOYEES.DEPARTMENT_ID%TYPE;
  3  	     v_first_name EMPLOYEES.FIRST_NAME%TYPE;
  4  	     v_last_name EMPLOYEES.LAST_NAME%TYPE;
  5  BEGIN
  6  	     SELECT DEPARTMENT_ID,FIRST_NAME,LAST_NAME
  7  	      INTO v_department_id,v_first_name,v_last_name
  8  	      FROM EMPLOYEES
  9  	      WHERE EMPLOYEE_ID =100;
 10  
 11  	     DBMS_OUTPUT.PUT_LINE('ID:'||v_department_id);
 12  	     DBMS_OUTPUT.PUT_LINE('NAME:'||v_first_name || ' ' ||v_last_name);
 13  END;
 14  /
ID:90
NAME:Steven King

PL/SQLプロシージャが正常に完了しました。

SQL> 

SQLでの実行結果と比較すると

SQL> SELECT DEPARTMENT_ID,FIRST_NAME,LAST_NAME
  2  FROM EMPLOYEES
  3  WHERE EMPLOYEE_ID =100;

DEPARTMENT_ID FIRST_NAME	   LAST_NAME
------------- -------------------- -------------------------
	   90 Steven		   King

SQLの実行結果と合致しています。正常にデータが取得できています。

プロシージャーとして登録する

SQL処理をプログラムとして登録できるPL/SQLは、所定の処理を記述しておき、それを呼び出す事で実際の処理部分の考慮やプログラミングを短縮できるので便利です。

今回、当たった仕事というのも、プログラム部分は新しい言語に書換するリプレース案件なのですが、データベース処理に関しては基本的にストアドプロシージャーが用意されていて、それを呼び出すものでした。

結果、全くではないものの、SQLの記述は殆ど無いという形になっていました。

早速、簡単なPL/SQLをプロシージャーとして登録してみます。

CREATE OR REPLACE PROCEDURE MYPROC
IS
	BEGIN
		DBMS_OUTPUT.PUT_LINE('プロシージャーを実行');
	END;
/

登録されたプロシージャーは、WindowsのA5からも確認できました。

データを出し入れするプロシージャー

SQLを実行するのですから、通常、パラメータを与え、結果を受け取る処理は必須になります。

PL/SQLの場合、IN指定で入力するパラメータに値を入れ、実行し、OUT指定の変数で結果を受け取ります。

データを取得する で使用したSELECT INTOを、プロシージャーにしてみましょう。

CREATE OR REPLACE PROCEDURE myout_param_proc(
	p_param1 IN NUMBER DEFAULT 0
	, p_returnid OUT NUMBER
	, p_fullname OUT VARCHAR2
)
IS
	v_department_id EMPLOYEES.DEPARTMENT_ID%TYPE;
	v_first_name EMPLOYEES.FIRST_NAME%TYPE;
	v_last_name EMPLOYEES.LAST_NAME%TYPE;
	v_id NUMBER;
BEGIN
	SELECT DEPARTMENT_ID,FIRST_NAME,LAST_NAME
	INTO v_department_id,v_first_name,v_last_name
	FROM EMPLOYEES
	WHERE EMPLOYEE_ID =p_param1;

	p_returnid := v_department_id;
	p_fullname := v_first_name || ' ' ||v_last_name;

END;
/

これをOracleデータベースのサーバーのsqlplusで実行すると、myout_param_proc というストアドが登録されます。

WindowsパソコンのA5からも確認でき、入力パラメータのp_param1に100を入力すれば、90とSteven King が返ってきます。

後は目的にあわせ、SQLを組み立てていき、必要なパラメータと、取得する結果を列記すれば、プロシージャーを呼び出すだけで処理が完結します。

プロシージャーをVB.NETから呼び出す

駆け足ですが、作成したVB.NETから、上記で作成したストアドプロシージャーを呼び出してみます。

基本は以前の記事で各データベースへの接続を参考に、プロジェクトにODP.NETをインストールし、接続モジュールを用意します。

Imports Oracle.ManagedDataAccess.Client

Module Module1

    Public oracleCon As New OracleConnection
    Public oracleCmd As New OracleCommand
    Public sqlCommand As New OracleCommand

    Sub sql_st()
        ''データベースに接続

        Dim Builder As OracleConnectionStringBuilder = New OracleConnectionStringBuilder()
        ' データベースに接続するために必要な情報をBuilderに与える
        Builder.DataSource = "ORACLE19C"
        Builder.UserID = "HR"
        Builder.Password = "HR"

        oracleCon.ConnectionString = Builder.ConnectionString
        'oracleCon.ConnectionString = "DATA SOURCE=ORACLE19C;USER ID=HR;PASSWORD=HR"
        oracleCon.Open()

    End Sub

    Sub sql_cl()
        ' データベースの切断
        oracleCon.Close()
    End Sub



End Module

Formには次のように記述しました。

Imports Oracle.ManagedDataAccess.Client

Public Class Form1
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Try
            sql_st()

            oracleCmd.Connection = oracleCon
            'コマンドタイプをストアドプロシージャにする
            oracleCmd.CommandType = CommandType.StoredProcedure
            '実行するストアドプロシージャを指定
            oracleCmd.CommandText = "myout_param_proc"
            'ストアドプロシージャの引数に渡す値の設定
            oracleCmd.Parameters.Add("p_param1", OracleDbType.Int32).Value = Integer.Parse(Me.TextBox1.Text)

            'ストアドプロシージャのout用パラメータ作成
            Dim outPara As New OracleParameter("p_returnid", OracleDbType.Int32)
            outPara.Direction = ParameterDirection.Output
            oracleCmd.Parameters.Add(outPara)

            Dim outPara2 As New OracleParameter("p_fullname", OracleDbType.Varchar2, 256)
            outPara2.Direction = ParameterDirection.Output
            oracleCmd.Parameters.Add(outPara2)


            'ストアドプロシージャの実行
            oracleCmd.ExecuteNonQuery()

            Me.TextBox2.Text = outPara.Value.ToString
            Me.TextBox3.Text = outPara2.Value.ToString

            MessageBox.Show("PROCEDURE3 正常終了 COUNT=" & outPara.Value.ToString(), "SUCCESS",
            MessageBoxButtons.OK, MessageBoxIcon.Information)

            sql_cl()

        Catch OraEx As OracleException
            'Oracle例外発生時
            MessageBox.Show(OraEx.Message, "ORACLE ERROR",
            MessageBoxButtons.OK, MessageBoxIcon.Stop)
            sql_cl()

        Catch ex As Exception
            '一般例外発生時
            MessageBox.Show(ex.Message, "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Stop)
            sql_cl()
        End Try
    End Sub
End Class

パラメーターとして、上のテキストボックスから値を取り、ストアドプロシージャーに送り、戻った結果をテキストボックス2つに格納しています。

返り値のVarchar2, 256 のように長さの指定が必要だったり、少々複雑な感じはしますが、決まった形状なので問題は無さそうです。

よりプログラムらしい動作

PL/SQLはプログラム言語なので、IF文による条件分岐や、FOR ループなどの処理がありますので、条件をつけて処理を分岐したり繰り返す事で複雑な処理を実装する事も可能です。

例えば、INでパラメータを与え、それを元にいくつかのテーブルを検索してデータを収集し、最終的に得られたデータでテーブルを検索して最終データを得るというような行程を組む事もできます。

簡単な例として先出のデータを出し入れするプロシージャーに幾つか変数を追加して、条件分岐を設定してみます。

CREATE OR REPLACE PROCEDURE myout_param_proc(
	p_param1 IN NUMBER DEFAULT 0
	, p_type IN VARCHAR2
	, p_date IN DATE
	, p_returnid OUT NUMBER
	, p_fullname OUT VARCHAR2
)
IS
	v_department_id EMPLOYEES.DEPARTMENT_ID%TYPE;
	v_first_name EMPLOYEES.FIRST_NAME%TYPE;
	v_last_name EMPLOYEES.LAST_NAME%TYPE;
	v_id NUMBER;
BEGIN


	IF p_type IS NULL THEN
		SELECT DEPARTMENT_ID,FIRST_NAME,LAST_NAME
		INTO v_department_id,v_first_name,v_last_name
		FROM EMPLOYEES
		WHERE EMPLOYEE_ID = p_param1;
	ELSE
		SELECT DEPARTMENT_ID,FIRST_NAME,LAST_NAME
		INTO v_department_id,v_first_name,v_last_name
		FROM EMPLOYEES
		WHERE HIRE_DATE = p_date;
	END IF;

	p_returnid := v_department_id;
	p_fullname := v_first_name || ' ' ||v_last_name;

END;
/

改修点は、p_type p_dateという変数を追加しました。

そのp_type がNullかどうかを判定し、Nullだったときは、今までと同じ動作をし、Null以外は、p_dateを日付の条件として、実行するSQLが変わるようにしました。

WindowsのA5から確認すると、パラメータが増えているのが判ります。

早速、実行してみましょう。

今回のPL/SQLでは、p_typeがNullかどうかで判定されますので、NULLの状態のまま、100を与えると、

SELECT
    DEPARTMENT_ID 
    , FIRST_NAME
    , LAST_NAME
FROM
    EMPLOYEES 
WHERE
    EMPLOYEE_ID = 100

---------
DEPARTMENT_ID	FIRST_NAME	LAST_NAME
90	Steven	King

が実行されます。

一方、100の数値を指定せず、p_typeになにか文字列を入れ、日付を指定すると、

SELECT
    DEPARTMENT_ID 
    , FIRST_NAME
    , LAST_NAME
FROM
    EMPLOYEES 
WHERE
    HIRE_DATE = TO_DATE('2008/03/24','YYYY/MM/DD')

------------
DEPARTMENT_ID	FIRST_NAME	LAST_NAME
80	Sundar	Ande

SQLとして、こちらが実行されます。

今回はNullかそうでないかの比較ですが、パラメーターから与える文字列で条件分岐すれば、より複雑なSQLの実行とその結果出力が可能です。

プロシージャーをVB.NETから呼び出す2

それでは、この改造ストアドプロシージャーをVB.NETから呼び出してみましょう。

まず、フォームを改造して、テキストボックスを一つ増やし、チェックボックスを新設します。

チェックボックスにチェックを入れたら、新しい日付での検索。

チェックボックスを空欄のままだと、番号で検索する従来の方法で呼び出すため、次のようにします。

    Private Sub CheckBox1_CheckedChanged(sender As Object, e As EventArgs) Handles CheckBox1.CheckedChanged
        If CheckBox1.Checked = True Then
            Me.TextBox1.Visible = False
            Me.TextBox4.Visible = True
        Else
            Me.TextBox1.Visible = True
            Me.TextBox4.Visible = False
        End If
    End Sub

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Me.CheckBox1.Checked = False
        Me.TextBox4.Visible = False

    End Sub

チェックのオン/オフで入力枠の表示/非表示を切り換えます。

初期はチェックがはずれているようにします。

しかし、次のコードは実際にはエラーが発生します。

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Try
            sql_st()

            oracleCmd.Connection = oracleCon
            'コマンドタイプをストアドプロシージャにする
            oracleCmd.CommandType = CommandType.StoredProcedure
            '実行するストアドプロシージャを指定
            oracleCmd.CommandText = "myout_param_proc"

            'ストアドプロシージャの引数に渡す値の設定
            ''チェックBOXで引き渡すパラメータを変更
            If CheckBox1.Checked = True Then
                oracleCmd.Parameters.Add("p_param1", OracleDbType.Int32).Value = DBNull.Value
                oracleCmd.Parameters.Add("p_type", OracleDbType.Int32).Value = "A"
                oracleCmd.Parameters.Add("p_date", OracleDbType.Date).Value =  CDate(Me.TextBox4.Text)

            Else
                'ID値
                oracleCmd.Parameters.Add("p_param1", OracleDbType.Int32).Value = Integer.Parse(Me.TextBox1.Text)
                oracleCmd.Parameters.Add("p_type", OracleDbType.Int32).Value = DBNull.Value
                oracleCmd.Parameters.Add("p_date", OracleDbType.Date).Value = DBNull.Value

            End If

            'ストアドプロシージャのout用パラメータ作成
            Dim outPara As New OracleParameter("p_returnid", OracleDbType.Int32)
            outPara.Direction = ParameterDirection.Output
            oracleCmd.Parameters.Add(outPara)

            Dim outPara2 As New OracleParameter("p_fullname", OracleDbType.Varchar2, 256)
            outPara2.Direction = ParameterDirection.Output
            oracleCmd.Parameters.Add(outPara2)


            'ストアドプロシージャの実行
            oracleCmd.ExecuteNonQuery()

            Me.TextBox2.Text = outPara.Value.ToString
            Me.TextBox3.Text = outPara2.Value.ToString

            MessageBox.Show("PROCEDURE3 正常終了 COUNT=" & outPara.Value.ToString(), "SUCCESS",
            MessageBoxButtons.OK, MessageBoxIcon.Information)

            sql_cl()

        Catch OraEx As OracleException
            'Oracle例外発生時
            MessageBox.Show(OraEx.Message, "ORACLE ERROR",
            MessageBoxButtons.OK, MessageBoxIcon.Stop)
            sql_cl()

        Catch ex As Exception
            '一般例外発生時
            MessageBox.Show(ex.Message, "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Stop)
            sql_cl()
        End Try
    End Sub

注意点という程でもないですが、データ型がかなりシビアです。

特にNullを代入するときは、通常、VB.NETで使用する DBNull.Value をそのまま代入しようとすると失敗します。

Nullをパラメータとして与える場合は、OracleParameterとしての変数をきちんと作成した上で代入する必要があります。

正しいコードは、次のようになります。

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Try
            sql_st()

            oracleCmd.Connection = oracleCon
            'コマンドタイプをストアドプロシージャにする
            oracleCmd.CommandType = CommandType.StoredProcedure
            '実行するストアドプロシージャを指定
            oracleCmd.CommandText = "myout_param_proc"

            'ストアドプロシージャの引数に渡す値の設定
            ''チェックBOXで引き渡すパラメータを変更
            If CheckBox1.Checked = True Then
                Dim inPara1 As New OracleParameter("p_param1", OracleDbType.Int32)
                inPara1.Direction = ParameterDirection.Input
                inPara1.Value = DBNull.Value
                oracleCmd.Parameters.Add(inPara1)

                oracleCmd.Parameters.Add("p_type", OracleDbType.Varchar2).Value = "A"

                oracleCmd.Parameters.Add("p_date", OracleDbType.Date).Value = CDate(Me.TextBox4.Text)

            Else
                'ID値

                oracleCmd.Parameters.Add("p_param1", OracleDbType.Int32).Value = Integer.Parse(Me.TextBox1.Text)

                Dim inPara1 As New OracleParameter("p_type", OracleDbType.Varchar2)
                inPara1.Direction = ParameterDirection.Input
                inPara1.Value = DBNull.Value
                oracleCmd.Parameters.Add(inPara1)

                Dim inPara2 As New OracleParameter("p_date", OracleDbType.Date)
                inPara2.Direction = ParameterDirection.Input
                inPara2.Value = DBNull.Value
                oracleCmd.Parameters.Add(inPara2)

            End If

            'ストアドプロシージャのout用パラメータ作成
            Dim outPara As New OracleParameter("p_returnid", OracleDbType.Int32)
            outPara.Direction = ParameterDirection.Output
            oracleCmd.Parameters.Add(outPara)

            Dim outPara2 As New OracleParameter("p_fullname", OracleDbType.Varchar2, 256)
            outPara2.Direction = ParameterDirection.Output
            oracleCmd.Parameters.Add(outPara2)


            'ストアドプロシージャの実行
            oracleCmd.ExecuteNonQuery()

            Me.TextBox2.Text = outPara.Value.ToString
            Me.TextBox3.Text = outPara2.Value.ToString

            MessageBox.Show("PROCEDURE3 正常終了 COUNT=" & outPara.Value.ToString(), "SUCCESS",
            MessageBoxButtons.OK, MessageBoxIcon.Information)

            sql_cl()

        Catch OraEx As OracleException
            'Oracle例外発生時
            MessageBox.Show(OraEx.Message, "ORACLE ERROR",
            MessageBoxButtons.OK, MessageBoxIcon.Stop)
            sql_cl()

        Catch ex As Exception
            '一般例外発生時
            MessageBox.Show(ex.Message, "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Stop)
            sql_cl()
        End Try
    End Sub

チェックを入れず、数値を入れるとID検索になり、ストアドが実行され、結果が表示されます。

チェックを入れると、テキストボックスの日付を与え、日付検索の結果が表示されています。

まとめ

今回のお仕事はDB周りはストアドに任せるものでしたのでVBのユーザーインターフェイスを作り、上記のような方法でストアドに接続してデータを得るというものでした。

ストアドの方は、DB部門が作ったものなので中身は見たくらいですが、プログラム言語としてはかなりいろいろな事ができますので、データベース処理はPL/SQLに記述し、それを呼び出す事でいろいろと面白い事ができそうです。

参考書籍にも書かれていましたが、特にクライアント機台数が多い場合、サーバーとのやりとりが、ストアドプロシージャーにパラメータを送る→結果を受け取る だけで済むため、トラフィックを大幅に節約できそうです。

また、DBチームとUIチームのように開発を分担し、必要なSQL問い合わせをストアドプロシージャ化すれば、開発の工程圧縮もできそうですね。

今後もいろいろ使えそうなので、自身のスキルとしていきたいと思いました。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

コラム

前の記事

VisualStudioとAccessの関係