AS400/IBMi SQLRPGの書き方 フリーフォームRPG

IT関連

書き方といって偉そうに投稿できるものではありませんが、文献が少ないと思うのでご参考になれば幸いです。

尚、これは自分の備忘録なので、間違いがあればご容赦を。

SQLRPGをなぜ使ったのか

例えば在庫照会のプログラムを作るとします。

商品情報が入った「商品マスタ」があり、在庫数が格納された「在庫ファイル」があるとします。

在庫照会なのでもちろんM「在庫ファイル」をメインでREADします。

その中で「商品マスタ」をCHAINもしくはJOINしレコードを完成させます。

なぜJOINするのか?商品名やサイズは「商品マスタ」にしか無いからです。

正規化するのが基本なので当たり前ですよね。

ところが今回、「商品マスタ」にある某カラム順に並べて表示してほしいという要望がありました。

それが事の発端です。

ちょっと何言っているかわからないかもしれませんが、あるんですそういう事例が。

(先人が作ったファイルレイアウトの致命的なミスかもしれません)

しかしこれ、CHAINで解決できますか?論理ファイルで解決できますか?OPNQRYFで解決できますか。

できないのです(たぶん)。論理ファイルでもJOINを使うことができますが、

論理ファイルのキーにはプライマリーファイルのフィールドしか指定できない。

という決まりがあるからです。IBMiのサイトに書かれてありました。

しかし、SQLを使えばいたって簡単。このように書くだけ。SQLを知っている方はなんとなく理解できると思います。

ポイントはORDERBYの中にJOINされる側のカラムが入っていることです。

論理ファイルでもJOINでもOPNQRYFでもそうですが、AS400の場合は並び順を変えようとしたら共にキーも変わってしまうのです。

これが大変です。

ゴチャゴチャ書きましたが、簡単に言うとサクっと並び順を変えて読みたいということです。

それをOPNQRYFでやろうとしたのがこちらの記事です。結局ダメでしたが参考までに。

AS400/IBMi OPNQRYFでJOINを使ってみる
前置き 私が思い出すための備忘録なので間違いがあるかもです。 逆にこういう使い方があるよというのがあれば教えてほしいです。 やりたいこと SYOHINという商品マスタがあり、IDとしてDAI/CYU/RENという3つのフ...

サンプルコード

見た方が早いのでいきなりサンプルコードです。

処理内容は在庫ファイルを商品マスタと結合して読んで、サブファイルに書き込んで表示します。

解説は後述します。

ファイル定義部分です。2つのファイルと画面ファイルの定義をしています。

定義部分です。END_OF_FILEという定数を定義します。後述します。

同じく定義です。SQLのSELECTで定義したものを入れる変数のようなものを作ります。これを定義しないと落ちます。

メインロジックです。

解説

ざっとこんな感じです。簡単に解説します。

1.EOL判定のための定数

EOLの判定についてですが、SQLで読む場合はREADの結果標識がありません。

IBMiのDB2に限らずOracleやMySQLでも同じですが、DBにSQLで命令したら、結果の状態を表わすリターンコードというのが返ってくるのでそれを使います。

正常終了は「00000」ですが、レコードが無い状態は「02000」というコードが返ってきます。

このリターンコードが02000かどうかを、IF文で確認することでEOFの判定を行います。

リターンコードはSQLSTATEという名前の変数で、これはユーザーが定義する必要はありませんが、それに対応する「02000」を定数で定義しておきます。

今回はEND_OF_FILEという定数名にしていますが、何でも大丈夫です。

2.ワークの指定

指定されたSQL文を元にREADみたいなことしますが、そのときにレコードのデータが保管されるワークです。

改善の余地があるかもしれませんが、SELECT文で指定したカラムとまったく同じ構成にしています。

3.カーソル宣言とSQLの指定

今回はWRITEやUPDATEやDELETEではなくファイルを読む系なので、カーソルというものがいるそうです。

あまりよく理解していませんが、カーソルとはファイルのどのレコードを指しているかを示すものでしょう。

DECLAREは日本語で宣言という意味です。私の場合はカーソル名をZAIKO_CSRにしましたが、好きな名前を付けてください。SQL文は自分で作ってください。

SQLはめちゃくちゃ簡単なので自分で勉強してください。

掘り下げればアホみたいにややこしい文も作れますが、SQLRPGではあまり凝ったものにしないほうがよさそうです。

SQLはこの辺を勉強すればよろしいかと思います。

4.カーソルのオープン

次にカーソルを開きます。先ほど定義したカーソル名を指定します。

宣言したものを使いますという指定でしょう。

5.読む

後は読んで必要な処理をするだけです。もちろんループで繰り返し読みます。

FETCHとは1件読む、いわゆるREADということです。

読んだ値を、INTO :[ワーク名]を使ってワークに代入します。

前述のとおりEND_OF_FILEには’02000’が入っています。

SQLがグルグル回るときにレコードが無ければSQLSTATEが’02000’になるということですね。

6.カーソルのクローズ

最後はカーソルをクローズして一連のSQLを終了します。

あまりよく分かっていませんが、メモリ空間からSQL定義などなどをクリアしているのかもです。

その他

ざっくりこんな感じです。作る上で気になった点があるので明記しておきます。

他にあれば追記します。

同じカーソル定義はプログラム内に重複できないみたい

同じカーソル名のSQLを作るとコンパイル自体が通らないみたい。

開いても閉じればいいと思ったがダメみたい。

CSR1とかCSR2にすれば大丈夫なので、SQLやカーソルはプログラム内に複数定義できるみたい。

SETLLができない

今回の場合に限って言えば、キーを替えたので従来使っていたSETLLができなくなりました。

ゆえに上記プログラムは実際にはもっと肥大化しています。

SQLでSETLLの代わりになるものといえばOFFSETがあり、これでレコードの何番目から読むというのを指定できますがやや大変です。

いかにSETLLとREADEが神なのかが良く分かりました。

以上です。FFRPGの書き方も備忘録があります。よろしければご覧ください。

AS400/IBMi フリーフォームRPGの書き方備忘録
私の備忘録です。順次追加していきます。 何も知らない初心者なので間違いがあればご指摘いただければ幸いです。 尚、RPGIVとRPGLEは厳密には違うようですが、ここではRPGLEに統一しておきます。 登場人物はRPG(II...

コメント

タイトルとURLをコピーしました