NEWS
IBM i の”新”必須言語 〜FFRPG入門〜 IBM i の”新”必須言語 〜FFRPG入門〜
2018.09.05

【FFRPG】第四回 データベース – SQL(照会プログラム)

【FFRPG】第四回 データベース – SQL(照会プログラム)

前回の復習

第三回プログラムの基本構造」では、FFRPG のソース・コードとプログラムの関係、基本的なステートメントと変数のスコープおよび記憶域について解説をしました。これらは FFRPG のプログラムを理解する上で避けて通れない知識です。この内容をベースに連載記事は進んでいきますので、何度も復習をして理解してください。 それでは、今回から複数回に渡ってデータベース・プログラミングを解説していきます。IBM i は OS に組み込まれたリレーショナル・データベース DB2 for i が標準のデータベースです。この RDB に記録された膨大な情報や、発生するトランザクション情報をいかに参照および記録していくのか。この SoR の領域をカバーしてきた言語が RPG です。まずは今回の記事で FFRPG で DB2 for i の情報を扱う基本的な仕組みをマスターしていきましょう。

データベース・プログラミング

RPG プログラムから DB2 for i へアクセスする方法は2通りあります。ひとつはネイティブ・アクセスであり、もうひとつは SQL アクセスです。 ネイティブ・アクセスは RPG プログラムが DB2 for i にアクセスする一般的な手法です。しかし、IBM i 独自の作成方法や名称があり、これから DB2 for i を勉強する方には初めてのことばかりで少し理解しにくいところがあるかもしれません。 DB2 for i は、他のリレーショナル・データベース製品で使われている SQL を使ったアクセスもサポートされているので、まずはこちらを使った FFRPG をサンプルにデータベース・プログラミングに慣れていきましょう。ネイティブ・アクセスについては第六回の記事で解説する予定です。

SQL

IBM i でサポートされている SQL は、他のプラットフォームでも利用されている SQL 標準に準拠していますので、IBM i 以外の技術者の方にもすぐに理解していただけると思います。SQL は FFRPG 内で記述することが可能で、SQL を通して FFRPG から DB2 for i のデータを処理することができます。SQL を記述した FFRPG プログラムは、以下のステップを経てプログラム・オブジェクトになります。
  • プリコンパイル
  • 静的 SQL ステートメントの準備
  • 変更されたソース・プログラムのコンパイル
SQL が組み込まれたプログラムはプリコンパイル(事前コンパイル)を実施して、SQL ステートメントを RPG コンパイラーが理解可能なステートメントに変換し、その後コンパイルすることで *PGM オブジェクトが作成されます。最後のコンパイルで使われるコマンドは CRTRPGMOD / CRTBNDRPG です。 上記の3つを一度に実行するためのコマンドが CRTSQLRPGI です。このコマンドを使用して作成できるオブジェクトは以下の3種類です。
  • プログラム(*PGM)
  • サービス・プログラム(*SRVPGM)
  • モジュール(*MODULE)
どのタイプのオブジェクトを作成するかは CRTSQLRPGI コマンドの OBJTYPE パラメータで指定します。このパラメータの省略値は *PGM なので、なにも指定しなければ作成されるオブジェクトは動的呼び出しが可能なプログラムということになります。

使用するテーブル

それでは、今回のプログラムで参照するテーブルを見ていきましょう。テーブル名は得意先マスターです。以下のようなデータを含んでいます。 このテーブルは以下の4つのカラムで構成されます。すべて文字タイプでカッコ内が桁数を表します。
  1. CSCSCD(5)- 得意先コード
  2. CSCSKN(20)- 得意先名称(カナ)
  3. CSCSKJ(20)- 得意先名称(漢字)
  4. CSADR1(20)- 得意住所1
得意先コードをプライマリー・キーとして設定していますので、得意先コードを指定すれば、参照される得意先情報は常に一意に識別されます(ユニーク制約)。

icafe004 プログラム(単一フィールド値の取得)

では実際のプログラム icafe004 の作成を通して、SQL を実行するためのステートメントを見ていきましょう。 EXEC SQL FFRPG プログラム内で SQL ステートメントを記述するには、EXEC SQL ステートメントを使用します。他のステートメント同様セミコロンで終わる点に注意してください。SQL 文は複数行にまたがって記述することができます。今回使用する SQL文は以下の通りです。 この SQL により、以下の検索が実行されます。
  • 検索対象テーブルは TECSMP(FROM)
  • 検索条件は、CSCSCD(得意先コード)が ‘01010’ のもの(WHERE)
  • 検索できたら、その得意先の名称を変数 customerName にセット(CSCSKJ INTO :customerName)
SQL で取得された値をプログラムで参照するには、検索した結果をプログラム変数に入れる必要があります。SQL 内で指定できる変数のことをホスト変数と言います。ホスト変数は FFRPG 内で定義が必要です。SQL 文内では、ホスト変数であることを示すために変数の前にコロンを指定します。上記 SQL 文では :customerName がホスト変数です。 ホスト変数は、取り出すフィールドとデータ・タイプの互換性がなければなりません。customerName には CSCSKJ の値をセットするので、同じデータ・タイプとして変数を定義する必要があります。 今回の例では、得意先コード ‘01010’ のデータを検索しているので、customerName 変数には「荒川薬局」がセットされます。 この SQL を組み込んだ FFRPG プログラム icafe004 のソース・コードは以下の通りです。 まず前回のプログラムと異なるところを説明します。 記述を削除したもの
  • ctl-opt dftname(iWorldxxxxx);
dftname キーワードを指定すると、プログラム作成コマンド(CRTBNDRPG)のプログラム名の省略値の値 *CTLSPEC が使えることは第二回の記事で説明しました。今回のプログラムでも使用できればよいのですが、SQL を含んだ FFRPG プログラムを作成するコマンドが CRTSQLRPGI で、このコマンドの最初の OBJ(作成するオブジェクト名を指定する)パラメータは入力必須のため、このコマンドを実行するごとに必ず指定しなければなりません。dftname キーワードが指定されていてもプログラムは作成されますが、今回は必要ないのであえて削除しています。 Orion で作成するファイルの拡張子 前回までのプログラムは、プログラム・コードを記述したファイルの拡張子は rpgle でしたが、今回は sqlrpgle にしています。この拡張子をみて、SQL が組み込まれているかどうかを判断することができるので、このように記述するようにしましょう。 コンパイル作業 前回までのプログラムは、5250 エミュレータでサイン・オン後に表示されるメニューのオプション1「プログラムの作成」を選択して行っていました。このオプションで実行されるのは CRTBNDRPG コマンドであり、このオプションは今回使用できません。組込 SQL プログラムのコンパイルコマンド CRTSQLRPGI を実行するためのオプション8「SQL プログラムの作成」を選択してください。 オプション選択後表示されるプロンプト画面では、「オブジェクト名」に作成するプログラム名を明示指定するのを忘れないでください。ソース・ストリーム・ファイルに指定するのは、Orion で作成したファイル名です。 追加のパラメーターの設定値は以下の通りです(F11 キーでキーワードが表示されます)。
  • COMPILEOPT(’TGTCCAID(5035)’)
Orion で作成されたファイルはユニコード形式で、そのままではコンパイラーが直接読むことができないために変換が必要なことは第一回で説明しました。この変換を行うよう指定するのが CRTBNDRPG / CRTRPGMOD コマンドの TGTCCSID パラメータです。今回は事前コンパイルをしなければならないので CRTSQLRPGI コマンドを使うのですが、このコマンドには TGTCCSID パラメータはありません。しかし、内部的に実行される CRTBNDRPG コマンドには設定が必要になるので、その設定値を指定するための COMPILEOPT パラメータに値を設定するキーワードとともに文字列として指定する必要があります。
  • RPGPPOPT(*LVL2)
SQL プリコンパイルを実行する前に事前処理を行うかどうかを指定するパラメータで、省略値は *NONE です。このパラメータを指定することにより、別のソースを参照する /COPY および /INCLUDE ディレクティブをコンパイラー前に展開するかどうかが決まります。 SQL のプリコンパイルも CRTBNDRPG / CRTRPGMOD コマンド同様にユニコード形式のファイルを処理することができません。つまりプリコンパイル前にもコード変換が必要になります。今回は /COPY も /INCLUDE も使っていませんが、このパラメータを指定することにより、その後のコンパイラーで使用する TGTCCSID の値を使ってコード変換を行い、プリコンパイラをその後で実行します。 このパラメータは *LVL1 および *LVL2 がありますが、今回はどちらを指定しても構いません(メニューのオプションでは *LVL2 を事前にセットしています)。 それでは Orion で icafe004.sqlrpgle ファイルを追加し、ソース・コードを登録して、プログラムのコンパイルを実行してみてください。出来上がったプログラムは *PGM なので、オプション2「プログラムの実行」で実行して結果を確認してください。dsply ステートメントで出力された情報を画面に表示する方法は覚えていますよね?得意先コード 01010 の名前「荒川薬局」が表示されるはずです。

icafe005 プログラム(複数フィールド値の取得)

icafe004 では、ホスト変数にセットするフィールドは一つだけでした。では、複数のフィールドの値を取得するにはどのように記述すればよいのでしょうか?この場合の SQL は以下のように記述します。 複数のフィールドの値を取得するには、SELECT の直後に取得したいフィールドをカンマで区切って記述します。そして、INTO の直後に取得したい複数フィールドの値をセットするホスト変数を同様にカンマで区切って記述します。ホスト変数の数とタイプはそれぞれ合っていなければならないので注意してください。 では、このプログラム icafe005 を作成してみましょう。 今回は dsply を二回実行していますので、「荒川薬局」と住所「東京都荒川区」が画面に表示されれば正解です。

icafe006 プログラム(データ構造を使用した複数フィールド値の取得)

取得するフィールド数が 4 つとか 5 つぐらいであれば、上記のような記述でも問題ないかもしれませんが、数十のフィールドを持つテーブルからデータを取得する場合はどうすればよいのでしょうか?例えば 100 ある場合は、それぞれ SELECT 直後に 100 フィールド、INTO 直後に 100 ホスト変数を記述することはできます。しかしこのような記述をするとソース・コードの見通しが悪くなってしまいます。そこで利用できるのがデータ構造です。 データ構造(データ・ストラクチャー)は、複数フィールドに対して名前を指定し、その名前で処理できるようにしたものです。具体的な例を見てみましょう。 データ構造は dcl-ds と end-ds で複数の変数を囲うようにして記述します。上記の例では、データ構造 customer は、内部に4つのサブ・フィールドを持ちます。サブ・フィールドはそれぞれ名前とデータ・タイプを指定します。この並び順は、今回の実習で使用している TECSMP テーブルの構造と同じである点に注意してください。 dcl-ds にqualified キーワードが指定されていますが、これを指定することにより、サブ・フィールドの参照は データ構造名での修飾が必須になります。
  • customer.CSCSCD など
これにより、同じ名前のサブ・フィールドでも、データ構造が異なれば定義して使用することが可能になります。 このデータ構造は、SQL のホスト構造として指定することができます。 SELECT 直後の * は、全てのフィールドを選択することを表しています。そして、その選択されたフィールドの値をセットするホスト構造として :cusotmer を指定しています。このように記述することで、テーブルのフィールド名がいつくあろうと対応するデータ構造を記述するだけで済みます。 ホスト構造を使用したプログラム・コードは以下の通りです。icafe006 プログラムとして作成してみましょう。 プログラム最後の dsply ですべてのフィールドの値を表示しています。実行結果はいかがでしたか?

icafe007 プログラム(EXNAME データ構造を使用した複数フィールド値の取得)

一般的に、テーブルはそれ自体にカラム情報を持っています。このカラム情報をコンパイラーが参照することができれば、データ構造の定義はより簡単になります。 上記サンプルでは、サブ・フィールドが定義されていません。そのかわり、extname キーワードが指定されています。このキーワードにはデータ構造のサブ・フィールド記述として使用されるフィールド記述が入っているテーブルの名前を指定します。 この定義によりTECSMP テーブルに定義されているカラム情報(名前、データ・タイプ、桁数など)からサブ・フィールドが自動的に定義されます。 フィールド数が多いテーブルでも、この記述方法だと簡単ですね。 実際のプログラム・コードは以下の通りです。icafe007 プログラムとして作成してみましょう。

演習問題

それでは演習問題です。得意先名を取得するサブ・プロシージャー getCustomerName を記述し、main プロシージャーから以下のように呼び出すプログラム icafe008 を作成してみましょう。 プログラムの構造、引数の受け渡しおよび値の戻しなどは icafe003.rpgle を参考にしてください。 【ヒント】getCustomerName プロシージャーで受け取った得意先コードは、select 文で使えるように記述しなければなりません。icafe007 までは、得意先コードは where 内で 文字リテラルで指定していますが、実はここもホスト変数を記述できます。 回答例は次回掲載します。頑張って icafe008 を完成させましょう。

終わりに

DB2 for i のテーブルのデータを SQL で参照するプログラムを解説しましたがいかがでしたか?各フィールドの参照方法や、extname キーワードを使用した便利なデータ構造定義方法など、実際の開発現場でもよく使用するものなので、しっかり理解してください。 今回は select 文で参照するレコードは常に1レコードでしたが、条件の指定方法によっては複数レコードが該当する場合ももちろんあるでしょう。次回はそのようなケースでのデータの参照方法や、更新および削除について解説する予定です。 どうぞお楽しみに!    

著者プロフィール

img_evolution_profile
いいねと思ったらシェア
twitter
facebook
hatena
IBM i の”新”必須言語 〜FFRPG入門〜 目次を見る

この連載は…

IBM i の”新”必須言語 〜FFRPG入門〜
関連記事
【FFRPG】第一回 とりあえず作ってみよう!
【FFRPG】第一回 とりあえず作ってみよう!
【FFRPG】第三回 プログラムの基本構造
【FFRPG】第三回 プログラムの基本構造
【FFRPG】第七回 データベース – ネイティブ・アクセス(更新、削除プログラム)
【FFRPG】第七回 データベース – ネイティブ・アクセス(更新、削除プログラム)
あなたにオススメの連載
できるIBM i 温故知新編
6記事
できるIBM i 温故知新編
IBM i の”新”必須言語 〜FFRPG入門〜
14記事
IBM i の”新”必須言語 〜FFRPG入門〜
IBM i アプリの第二の柱 OSS
15記事
IBM i アプリの第二の柱 OSS
PAGE TOP