Browsing with START and READ NEXT
Random reads answer "give me account 100200". Plenty of questions are
ranges instead: every policy starting IE, every order from 1 March,
every customer in Cork. For those you position the file with START,
then read forward with READ ... NEXT. This is called a browse.
START on the record key
IDENTIFICATION DIVISION.
PROGRAM-ID. BROWSE.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT PART-FILE ASSIGN TO PARTMAST
ORGANIZATION IS INDEXED
ACCESS MODE IS DYNAMIC
RECORD KEY IS PART-NO
FILE STATUS IS WS-FS.
DATA DIVISION.
FILE SECTION.
FD PART-FILE.
01 PART-REC.
05 PART-NO PIC X(4).
05 PART-DESC PIC X(12).
WORKING-STORAGE SECTION.
01 WS-FS PIC XX.
01 WS-EOF PIC X VALUE "N".
PROCEDURE DIVISION.
OPEN OUTPUT PART-FILE
MOVE "A100BOLT M8" TO PART-REC
WRITE PART-REC
MOVE "B200WASHER" TO PART-REC
WRITE PART-REC
MOVE "B350NUT M8" TO PART-REC
WRITE PART-REC
MOVE "C010SPRING" TO PART-REC
WRITE PART-REC
CLOSE PART-FILE
OPEN INPUT PART-FILE
MOVE "B000" TO PART-NO
START PART-FILE KEY IS NOT LESS THAN PART-NO
INVALID KEY MOVE "Y" TO WS-EOF
END-START
PERFORM UNTIL WS-EOF = "Y"
READ PART-FILE NEXT RECORD
AT END MOVE "Y" TO WS-EOF
NOT AT END
IF PART-NO(1:1) = "B"
DISPLAY PART-NO " " PART-DESC
ELSE
MOVE "Y" TO WS-EOF
END-IF
END-READ
END-PERFORM
CLOSE PART-FILE
STOP RUN.
Output:
B200 WASHER
B350 NUT M8
B000 does not exist, and it doesn't need to: KEY IS NOT LESS THAN
(also written >=) positions at the first key that is equal or higher.
START reads nothing into the record area; it only sets the position.
The first READ NEXT then returns B200.
Two things end a browse:
- AT END (status
10): you ran off the end of the file. - The key moves out of range. VSAM doesn't know your range, so you test
it yourself on every record, here
PART-NO(1:1) = "B".
If no key satisfies the START condition you get INVALID KEY, status
23. The usual relations are EQUAL TO (=), GREATER THAN (>) and
NOT LESS THAN (>=).
START on an alternate key
With ALTERNATE RECORD KEY IS CUST-CITY WITH DUPLICATES in the SELECT, you
can START on that field instead:
MOVE "CORK" TO CUST-CITY
START CUST-FILE KEY IS EQUAL TO CUST-CITY
INVALID KEY DISPLAY "NO CUSTOMERS IN CORK"
END-START
The key named in START becomes the key of reference: each
READ NEXT now follows the city index, visiting every Cork record, then
the next city alphabetically, and so on. Test the city on every record and
stop when it changes.
Why ACCESS DYNAMIC
START and READ NEXT are sequential verbs. With ACCESS SEQUENTIAL you
can browse but not do random reads; with RANDOM you cannot browse at all.
DYNAMIC gives you both in one program, which is what most maintenance
and inquiry programs use.
On the job
On IBM, reading through an alternate key with duplicates returns status
02 (not 00) when more records with the same alternate key follow.
Code like IF WS-FS = "00" then treats a good read as an error. Test
WS-FS(1:1) = "0", or define an 88-level with both values, to be
safe on every platform. (GnuCOBOL, which runs these exercises, returns
00.)
Your task
Customer service wants every customer in a given city. The customer master has an alternate index on city.
DD CUSTMAST — indexed, 35-byte records:
| Field | PIC | Key |
|---|---|---|
CUST-ID |
X(5) |
record key |
CUST-NAME |
X(20) |
|
CUST-CITY |
X(10) |
alternate key, with duplicates |
Input (stdin): one city per line, ending with END.
For each city display CITY: and the city, then each matching customer
as two spaces, CUST-ID, a space, CUST-NAME, then COUNT: nnn.
If there are none, display NO CUSTOMERS instead (no count line).
CITY: CORK
C0002 MARY BYRNE
C0005 SEAN WALSH
COUNT: 002
CITY: SLIGO
NO CUSTOMERS
Don't read the whole file: position with START and stop as soon as the
city changes.