7.26.4 DEF_LIST Examples

Example 1: Write an RDML program to display the full details of an order.

Define the order line list required with name #ORDERLINE and group the fields required from the order header file under the name #ORDERHEAD:

DEF_LIST   NAME(#ORDERLINE) FIELDS(#ORDLIN #PRODUCT #QUANTITY #PRICE)

GROUP_BY   NAME(#ORDERHEAD) FIELDS(#ORDNUM #CUSTNUM #DATEDUE)

Ask the user to input an order number, clear all entries from the list and set mode to display:

L1: REQUEST    FIELDS(#ORDNUM)

    SET_MODE   TO(*DISPLAY)

    CLR_LIST   NAMED(#ORDERLINE)

Fetch the required fields from the ORDHDR file. If not found return to REQUEST command with an automatic error message:

FETCH      FIELDS(#ORDERHEAD) FROM_FILE(ORDHDR)  WITH_KEY(#ORDNUM) NOT_FOUND(L1)  ISSUE_MSG(*YES)

Select the required fields from the ORDLIN file. For each record selected add a new entry to the list named #ORDERLINE:

SELECT     FIELDS(#ORDERLINE) FROM_FILE(ORDLIN) WITH_KEY(#ORDNUM)

ADD_ENTRY  TO_LIST(#ORDERLINE)

ENDSELECT

Finally display the order header fields and order line details to the user:

DISPLAY    FIELDS(#ORDERHEAD) BROWSELIST(#ORDERLINE)

The screen formats automatically designed by LANSA for this RDML program would look something like this:

For the REQUEST FIELDS(#ORDNUM) command:

 

         Order number : ______________

 

 

For DISPLAY FIELDS(#ORDERHEAD) BROWSELIST(#ORDERLINE) command:

 

         Order number : 99999999                           

         Customer no  : 999999                             

         Date due     : 99/99/99                           

                                                           

         Line                                              

         No   Product Quantity Price                       

         99   9999999  99999  99999.99                     

         99   9999999  99999  99999.99                     

         99   9999999  99999  99999.99                     

         99   9999999  99999  99999.99                     

         99   9999999  99999  99999.99                     

         99   9999999  99999  99999.99                     

                                                           

 

 

Example 2: Modify the RDML program used in the previous example to include the field #PDESC (product description) from the PROMST (product master) file into the list:

Include #PDESC into the list definition.

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)

Select the required fields from the ORDLIN file. For each record selected get the associated product description then add a new entry to the list named #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)

The screen formats automatically designed by LANSA for this amended RDML program would now look something like this:

For the REQUEST FIELDS(#ORDNUM) command:

 

         Order number :  ___________________

 

 

For DISPLAY FIELDS(#ORDERHEAD) BROWSELIST(#ORDERLINE) command:

        

  Order number : 99999999                           

  Customer no  : 999999                             

  Date due     : 99/99/99                           

                                                           

  Line                                              

  No   Product Description        Quantity Price    

  99   9999999 XXXXXXXXXXXXXXXXXXXX 99999  99999.99 

  99   9999999 XXXXXXXXXXXXXXXXXXXX 99999  99999.99 

  99   9999999 XXXXXXXXXXXXXXXXXXXX 99999  99999.99 

  99   9999999 XXXXXXXXXXXXXXXXXXXX 99999  99999.99 

  99   9999999 XXXXXXXXXXXXXXXXXXXX 99999  99999.99 

  99   9999999 XXXXXXXXXXXXXXXXXXXX 99999  99999.99 

                                                           

 

 

Example 3: Consider the following simple RDML program that requests the user inputs the surname (fully or partially), then displays a list of all employees whose names start with the value specified:

********   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

This program will work just fine, but what if the user inputs a search name of "D", and 800 employees working for the company have a surname that starts with "D"?

The result will be a list containing 800 names. But more importantly, it will take a long time to build up the list and use a lot of computer resource while doing it.

To solve this problem, a technique called "page at a time" browsing is often used. What this basically means is that the program extracts one "page" of names matching the request, and then displays them to the user. If the user presses the roll up key then the next page is fetched and displayed, etc, etc.

To implement a "page at a time" technique for this particular program it could be modified like this:

The commands that have been inserted or changed are in red font.

********   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

The "page at a time" technique described here can be applied to just about any situation where a browse list is to be displayed and can considerably improve performance in most of them.

It is easy to modify existing programs that use SELECT and DISPLAY (like the inital example here) to use the page at a time technique. Note how the new logic "slots into" the existing logic with no major structural change to the program logic/flow.

The easiest way to implement "page at a time" techniques is to design and fully test a standard "algorithm" that is suitable for your site's needs. This can then be used as a base or template for all future applications.

Example 4: A transaction file called TRANS is to be printed and contains 10,000 records. For each transaction printed the associated state description must be extracted from file STATES and printed as well.

A simple RDML program to do this might look like this:

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

However, by using a working list the speed of this program can be improved considerably:

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

If there were 10 states, then this version of the print program would do 9,990 less database accesses than the first version.

Note that exactly the same performance improvement can be achieved more simply by using the KEEP_LAST parameter of the FETCH command like this:

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