Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

[ Image Added |../../index.htm#lansa/def_list_e.htm]
現在地:

Anchor
_Ref428885216
_Ref428885216
Anchor
_

...

Toc139468568
_

...

Toc139468568
7.26.4 DEF_LIST の使用例

例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)コマンドの場合:

...

例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  
[ Image Added |../../index.htm#lansa/def_list_e.htm]