例1:注文の明細をすべて表示するRDMLプログラムを作成します。
必要な明細行リストを名前#ORDERLINEで定義し、注文頭書きファイルの必要なフィールドを名前#ORDERHEADでグループ化します。
DEF_LIST NAME(#ORDERLINE) FIELDS(#ORDLIN #PRODUCT #QUANTITY #PRICE)
GROUP_BY NAME(#ORDERHEAD) FIELDS(#ORDNUM #CUSTNUM #DATEDUE)
ユーザーに注文番号を入力するよう要求し、リスト内のすべての項目をクリアして表示モードに設定します。
L1: REQUEST FIELDS(#ORDNUM)
SET_MODE TO(*DISPLAY)
CLR_LIST NAMED(#ORDERLINE)
必要なフィールドをORDHDRファイルから取得します。見つからなかった場合は、自動エラー・メッセージと共にREQUESTコマンドに戻ります。
FETCH FIELDS(#ORDERHEAD) FROM_FILE(ORDHDR) WITH_KEY(#ORDNUM) NOT_FOUND(L1) ISSUE_MSG(*YES)
ORDLINファイルから必要なフィールドを選択します。選択したレコードごとに、新しい項目を#ORDERLINEという名前のリストに追加します。
SELECT FIELDS(#ORDERLINE) FROM_FILE(ORDLIN) WITH_KEY(#ORDNUM)
ADD_ENTRY TO_LIST(#ORDERLINE)
ENDSELECT
最後に、注文のヘッダー・フィールドと明細行の詳細をユーザーに表示します。
DISPLAY FIELDS(#ORDERHEAD) BROWSELIST(#ORDERLINE)
LANSAがこのRDMLプログラム用に自動的に設計する画面形式は以下のようになります。
REQUEST FIELDS(#ORDNUM)コマンドの場合:
|
DISPLAY FIELDS(#ORDERHEAD) BROWSELIST(#ORDERLINE)コマンドの場合:
|
例2:上記の例で使用したRDMプログラムを変更し、PROMST (製品マスター)ファイルのフィールド#PDESC (製品の説明)をリストに含めます。
リスト定義に#PDESCを含めます。
DEF_LIST NAME(#ORDERLINE) FIELDS(#ORDLIN #PRODUCT #PDESC #QUANTITY #PRICE)
GROUP_BY NAME(#ORDERHEAD) FIELDS(#ORDNUM #CUSTNUM #DATEDUE)
L1: REQUEST FIELDS(#ORDNUM)
SET_MODE TO(*DISPLAY)
CLR_LIST NAMED(#ORDERLINE)
FETCH FIELDS(#ORDERHEAD) FROM_FILE(ORDHDR) WITH_KEY(#ORDNUM) NOT_FOUND(L1) ISSUE_MSG(*YES)
ORDLINファイルから必要なフィールドを選択します。選択したレコードごとに、関連付けられた製品の説明を取得し、新しい項目を#ORDERLINEというリストに追加します。
SELECT FIELDS(#ORDERLINE) FROM_FILE(ORDLIN) WITH_KEY(#ORDNUM)
FETCH FIELDS(#PDESC) FROM_FILE(PROMST) WITH_KEY(#PRODUCT)
ADD_ENTRY TO_LIST(#ORDERLINE)
ENDSELECT
DISPLAY FIELDS(#ORDERHEAD) BROWSELIST(#ORDERLINE)
LANSAがこの変更後のRDMLプログラム用に自動的に設計する画面形式は以下のようになります。
REQUEST FIELDS(#ORDNUM)コマンドの場合:
|
DISPLAY FIELDS(#ORDERHEAD) BROWSELIST(#ORDERLINE)コマンドの場合:
|
例3:姓(すべてまたは一部)を入力するようユーザーに要求し、指定された値で名前が始まるすべての社員のリストを表示する、以下の単純なRDMLプログラムについて考えます。
******** Define work variables and browse list to be used
DEFINE FIELD(#L1COUNT) TYPE(*DEC) LENGTH(7) DECIMALS(0)
DEF_LIST NAME(#L1) FIELDS((#SURNAME) (#GIVENAME) (#EMPNO) (#ADDRESS1)) COUNTER(#L1COUNT)
******** Loop until terminated by EXIT or CANCEL
BEGIN_LOOP
******** Get surname to search for
REQUEST FIELDS(#SURNAME)
******** Build list of generically identical names
CLR_LIST NAMED(#L1)
SELECT FIELDS(#L1) FROM_FILE(PSLMST2) WITH_KEY(#SURNAME) GENERIC(*YES)
ADD_ENTRY TO_LIST(#L1)
ENDSELECT
******** If names found, display list to user
IF COND('#L1COUNT *GT 0')
DISPLAY BROWSELIST(#L1)
******** else issue error indicating none found
ELSE
MESSAGE MSGTXT('No employees have a surname matching request')
ENDIF
******** Loop back and request next name to search for
END_LOOP
機能的にはこれで充分ですが、例えば検索キーとして「D」を指定し、これに合致する従業員が800人いたとすればどうなるでしょうか。
この場合、800行ものリストが表示されることになってしまい、ユーザーにとって見にくい上に、相当の時間とコンピュータ資源を要します。
これを解消するため、所定の行数ごとにページで区切って表示する方法がよく使われます。すなわち、条件に合致するレコードを「1ページ分」だけ検索し、これを表示するという方法です。次のページに進むためのキーが押されれば、改めてレコードを検索し、表示することになります。
このプログラムに「ページ単位」技法を実装するには、以下のように変更します。
挿入もしくは変更されたコマンドは赤で示されています。
******** Define work variables and browse list to be used
DEFINE FIELD(#L1COUNT) TYPE(*DEC) LENGTH(7) DECIMALS(0)
DEFINE FIELD(#L1PAGE) TYPE(*DEC) LENGTH(7) DECIMALS(0)
DEFINE FIELD(#L1TOP) TYPE(*DEC) LENGTH(7) DECIMALS(0)
DEFINE FIELD(#L1POS) TYPE(*CHAR) LENGTH(7)
DEF_LIST NAME(#L1) FIELDS((#SURNAME) (#GIVENAME) (#EMPNO) (#ADDRESS1)) COUNTER(#L1COUNT) PAGE_SIZE(#L1PAGE) TOP_ENTRY(#L1TOP) SCROLL_TXT(#L1POS)
******** Loop until teminated by EXIT or CANCEL
BEGIN_LOOP
******** Get surname to search for
REQUEST FIELDS(#SURNAME)
******** Build list of generically identical names
CLR_LIST NAMED(#L1)
CHANGE FIELD(#IO$KEY) TO(UP)
CHANGE FIELD(#L1TOP) TO(1)
SELECT FIELDS(#L1) FROM_FILE(PSLMST2) WITH_KEY(#SURNAME) GENERIC(*YES) WHERE('#IO$KEY = UP') OPTIONS(*ENDWHERE)
EXECUTE SUBROUTINE(DISPLAY) WITH_PARMS('''More...''')
ADD_ENTRY TO_LIST(#L1)
ENDSELECT
******** If names found, display list to user
IF COND('#L1COUNT *GT 0')
EXECUTE SUBROUTINE(DISPLAY) WITH_PARMS('''Bottom''')
******** else issue error indicating none found
ELSE
MESSAGE MSGTXT('No employees have a surname matching request')
ENDIF
******** Loop back and request next name to search for
END_LOOP
********
******** Display names if page is full or list is complete
********
SUBROUTINE NAME(DISPLAY) PARMS(#L1POS)
DEFINE FIELD(#L1REMN) TYPE(*DEC) LENGTH(5) DECIMALS(5)
CHANGE FIELD(#L1REMN) TO('#L1COUNT / #L1PAGE')
IF COND('(#L1COUNT *NE 0) *AND (#IO$KEY = UP) *AND ((#L1POS = ''Bottom'') *OR (#L1REMN *EQ 0.00000))')
DOUNTIL COND('(#L1POS *NE ''Bottom'') *OR (#IO$KEY *NE UP)')
DISPLAY BROWSELIST(#L1) USER_KEYS((*ROLLUP))
ENDUNTIL
CHANGE FIELD(#L1TOP) TO('#L1TOP + #L1PAGE')
ENDIF
ENDROUTINE
この手法は、表示するリストの行数が膨大になりうる状況で一般的に使えるもので、処理性能の向上にも効果があります。
「最初の例」に挙げたような、SELECTとDISPLAYを組み合わせて実装したプログラムは、この手法を取り入れて比較的簡単に最適化できます。プログラム構成や処理の流れにはあまり手を入れず、局所的な修正で対処できることがわかるでしょう。
この手法を実際に組み込むためには、サイトの要求に合致した「標準」アルゴリズムを設計し、充分にテストしておくとよいでしょう。これをテンプレートとして個々のアプリケーションに適用することができます。
例4:TRANSという取引ファイルを印刷します。このファイルには、10,000個のレコードが保持されています。印刷する取引ごとに、それに関連付けられた州の記述をファイルSTATESから抽出して印刷する必要があります。
この操作を実行する単純なRDMLプログラムは以下のようになります。
GROUP_BY NAME(#TRANS) FIELDS(#TRANNUM #TRANTIME #TRANDATE #TRANTYPE #TRANUSER #TRANSTATE #STATEDES)
SELECT FIELDS(#TRANS) FROM_FILE(TRANS)
FETCH FIELDS(#TRANS) FROM_FILE(STATES) WITH_KEY(#TRANSTATE)
UPRINT FIELDS(#TRANS)
ENDSELECT
ただし、作業リストを使用すれば、このプログラムを大幅に高速化できます。
GROUP_BY NAME(#TRANS) FIELDS(#TRANNUM #TRANTIME #TRANDATE #TRANTYPE #TRANUSER #TRANSTATE #STATEDES)
DEF_LIST NAME(#STATES) FIELDS(#STATE #STATEDES) TYPE(*WORKING) ENTRYS(10)
SELECT FIELDS(#STATES) FROM_FILE(STATE)
ADD_ENTRY TO_LIST(#STATES)
ENDSELECT
SELECT FIELDS(#TRANS) FROM_FILE(TRANS)
LOC_ENTRY IN_LIST(#STATES) WHERE('#STATE = #TRANSTATE')
UPRINT FIELDS(#TRANS)
ENDSELECT
州が10個ある場合、この印刷プログラムでは、最初のバージョンよりもデータベース・アクセスが9,990回少なくなります。
以下のように、FETCHコマンドのKEEP_LASTパラメータを使用することにより、さらに簡単な方法でまったく同じようにパフォーマンスを高めることができます。
GROUP_BY NAME(#TRANS) FIELDS(#TRANNUM #TRANTIME #TRANDATE #TRANTYPE #TRANUSER #TRANSTATE #STATEDES)
SELECT FIELDS(#TRANS) FROM_FILE(TRANS)
FETCH FIELDS(#TRANS) FROM_FILE(STATES) WITH_KEY(#TRANSTATE) KEEP_LAST(10)
UPRINT FIELDS(#TRANS)
ENDSELECT