The ALTERNATE clause represents one of COBOL's most sophisticated and powerful file organization mechanisms, serving as the primary tool for defining alternate keys in indexed files that enable multiple access paths to the same data records. Far more than a simple file access method, the ALTERNATE clause embodies COBOL's comprehensive approach to data organization by providing secondary indexing capabilities, multiple sort sequences, flexible data retrieval patterns, and advanced file navigation techniques that enable applications to access the same data through different logical views while maintaining data integrity, performance optimization, and sophisticated query capabilities that are essential for complex business applications requiring multiple data access patterns and comprehensive information retrieval systems.
In enterprise computing environments, the ALTERNATE clause serves as a critical foundation for advanced database-like functionality within COBOL file systems, enabling developers to create sophisticated data access applications that support multiple search criteria, implement complex reporting requirements, provide flexible data navigation, and maintain high-performance data retrieval capabilities. Its capabilities extend far beyond simple sequential access to encompass sophisticated indexing strategies, duplicate key handling, partial key searches, and integration with modern database concepts that are essential for applications requiring comprehensive data access flexibility and enterprise-grade file management capabilities that support complex business data organization requirements and advanced information retrieval patterns.
12345678910111213141516171819202122232425262728*> Basic ALTERNATE key definition in SELECT statement SELECT CUSTOMER-FILE ASSIGN TO "CUSTOMER.DAT" ORGANIZATION IS INDEXED ACCESS MODE IS DYNAMIC RECORD KEY IS CUSTOMER-ID ALTERNATE RECORD KEY IS CUSTOMER-NAME ALTERNATE RECORD KEY IS CUSTOMER-ZIP-CODE ALTERNATE RECORD KEY IS CUSTOMER-PHONE FILE STATUS IS CUSTOMER-FILE-STATUS. *> File record structure FD CUSTOMER-FILE. 01 CUSTOMER-RECORD. 05 CUSTOMER-ID PIC X(10). 05 CUSTOMER-NAME PIC X(30). 05 CUSTOMER-ADDRESS PIC X(50). 05 CUSTOMER-CITY PIC X(20). 05 CUSTOMER-STATE PIC X(2). 05 CUSTOMER-ZIP-CODE PIC X(10). 05 CUSTOMER-PHONE PIC X(15). 05 CUSTOMER-EMAIL PIC X(40). 05 CUSTOMER-STATUS PIC X(10). *> Working storage for key fields 01 WS-SEARCH-KEYS. 05 WS-SEARCH-NAME PIC X(30). 05 WS-SEARCH-ZIP PIC X(10). 05 WS-SEARCH-PHONE PIC X(15).
Basic ALTERNATE key definitions create secondary access paths to indexed file data.
1234567891011121314151617181920212223242526272829303132*> ALTERNATE keys allowing duplicate values SELECT EMPLOYEE-FILE ASSIGN TO "EMPLOYEE.DAT" ORGANIZATION IS INDEXED ACCESS MODE IS DYNAMIC RECORD KEY IS EMPLOYEE-ID ALTERNATE RECORD KEY IS DEPARTMENT-CODE WITH DUPLICATES ALTERNATE RECORD KEY IS SALARY-GRADE WITH DUPLICATES ALTERNATE RECORD KEY IS HIRE-DATE WITH DUPLICATES ALTERNATE RECORD KEY IS LAST-NAME WITH DUPLICATES FILE STATUS IS EMPLOYEE-FILE-STATUS. *> Employee record structure FD EMPLOYEE-FILE. 01 EMPLOYEE-RECORD. 05 EMPLOYEE-ID PIC X(8). 05 FIRST-NAME PIC X(20). 05 LAST-NAME PIC X(25). 05 DEPARTMENT-CODE PIC X(5). 05 SALARY-GRADE PIC X(3). 05 HIRE-DATE PIC X(8). 05 SALARY-AMOUNT PIC 9(7)V99. 05 MANAGER-ID PIC X(8). 05 EMPLOYEE-STATUS PIC X(10). *> Search criteria for duplicate keys 01 WS-DEPARTMENT-SEARCH. 05 WS-DEPT-CODE PIC X(5). 05 WS-DEPT-COUNTER PIC 9(5) VALUE 0. 01 WS-SALARY-SEARCH. 05 WS-SALARY-GRADE PIC X(3). 05 WS-SALARY-COUNTER PIC 9(5) VALUE 0.
WITH DUPLICATES clause allows multiple records with the same alternate key value.
123456789101112131415161718192021222324252627282930313233343536373839404142434445*> Complex ALTERNATE keys with compound fields SELECT INVENTORY-FILE ASSIGN TO "INVENTORY.DAT" ORGANIZATION IS INDEXED ACCESS MODE IS DYNAMIC RECORD KEY IS ITEM-ID ALTERNATE RECORD KEY IS CATEGORY-SUBCATEGORY-KEY = ITEM-CATEGORY, ITEM-SUBCATEGORY ALTERNATE RECORD KEY IS SUPPLIER-ITEM-KEY = SUPPLIER-CODE, ITEM-NUMBER WITH DUPLICATES ALTERNATE RECORD KEY IS LOCATION-STATUS-KEY = WAREHOUSE-LOCATION, ITEM-STATUS ALTERNATE RECORD KEY IS PRICE-RANGE-KEY = PRICE-CATEGORY, ITEM-PRIORITY WITH DUPLICATES FILE STATUS IS INVENTORY-FILE-STATUS. *> Inventory record with compound key fields FD INVENTORY-FILE. 01 INVENTORY-RECORD. 05 ITEM-ID PIC X(12). 05 ITEM-NUMBER PIC X(15). 05 ITEM-DESCRIPTION PIC X(50). 05 ITEM-CATEGORY PIC X(10). 05 ITEM-SUBCATEGORY PIC X(10). 05 SUPPLIER-CODE PIC X(8). 05 WAREHOUSE-LOCATION PIC X(6). 05 ITEM-STATUS PIC X(10). 05 PRICE-CATEGORY PIC X(5). 05 ITEM-PRIORITY PIC X(3). 05 UNIT-PRICE PIC 9(6)V99. 05 QUANTITY-ON-HAND PIC 9(8). 05 REORDER-LEVEL PIC 9(6). *> Compound key search structures 01 WS-COMPOUND-KEYS. 05 WS-CATEGORY-SUBCATEGORY-KEY. 10 WS-SEARCH-CATEGORY PIC X(10). 10 WS-SEARCH-SUBCATEGORY PIC X(10). 05 WS-SUPPLIER-ITEM-KEY. 10 WS-SEARCH-SUPPLIER PIC X(8). 10 WS-SEARCH-ITEM-NUM PIC X(15). 05 WS-LOCATION-STATUS-KEY. 10 WS-SEARCH-LOCATION PIC X(6). 10 WS-SEARCH-STATUS PIC X(10).
Compound ALTERNATE keys combine multiple fields for sophisticated data organization.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507IDENTIFICATION DIVISION. PROGRAM-ID. ALTERNATE-KEY-DEMO. ENVIRONMENT DIVISION. INPUT-OUTPUT SECTION. FILE-CONTROL. *> Customer master file with multiple alternate keys SELECT CUSTOMER-MASTER-FILE ASSIGN TO "CUSTMAST.DAT" ORGANIZATION IS INDEXED ACCESS MODE IS DYNAMIC RECORD KEY IS CUSTOMER-ID ALTERNATE RECORD KEY IS CUSTOMER-NAME WITH DUPLICATES ALTERNATE RECORD KEY IS CUSTOMER-ZIP-CODE WITH DUPLICATES ALTERNATE RECORD KEY IS CUSTOMER-PHONE ALTERNATE RECORD KEY IS CUSTOMER-EMAIL ALTERNATE RECORD KEY IS ACCOUNT-STATUS-KEY = ACCOUNT-STATUS, CREDIT-RATING WITH DUPLICATES FILE STATUS IS CUSTOMER-FILE-STATUS. *> Transaction file with alternate keys SELECT TRANSACTION-FILE ASSIGN TO "TRANS.DAT" ORGANIZATION IS INDEXED ACCESS MODE IS DYNAMIC RECORD KEY IS TRANSACTION-ID ALTERNATE RECORD KEY IS CUSTOMER-TRANS-KEY = CUSTOMER-ID, TRANSACTION-DATE WITH DUPLICATES ALTERNATE RECORD KEY IS DATE-TYPE-KEY = TRANSACTION-DATE, TRANSACTION-TYPE WITH DUPLICATES ALTERNATE RECORD KEY IS AMOUNT-RANGE-KEY = AMOUNT-CATEGORY, TRANSACTION-STATUS WITH DUPLICATES FILE STATUS IS TRANSACTION-FILE-STATUS. DATA DIVISION. FILE SECTION. FD CUSTOMER-MASTER-FILE. 01 CUSTOMER-MASTER-RECORD. 05 CUSTOMER-ID PIC X(10). 05 CUSTOMER-NAME PIC X(30). 05 CUSTOMER-ADDRESS PIC X(50). 05 CUSTOMER-CITY PIC X(20). 05 CUSTOMER-STATE PIC X(2). 05 CUSTOMER-ZIP-CODE PIC X(10). 05 CUSTOMER-PHONE PIC X(15). 05 CUSTOMER-EMAIL PIC X(40). 05 ACCOUNT-STATUS PIC X(10). 05 CREDIT-RATING PIC X(5). 05 ACCOUNT-BALANCE PIC S9(8)V99. 05 LAST-ACTIVITY-DATE PIC X(8). FD TRANSACTION-FILE. 01 TRANSACTION-RECORD. 05 TRANSACTION-ID PIC X(15). 05 CUSTOMER-ID PIC X(10). 05 TRANSACTION-DATE PIC X(8). 05 TRANSACTION-TYPE PIC X(10). 05 TRANSACTION-AMOUNT PIC S9(8)V99. 05 AMOUNT-CATEGORY PIC X(5). 05 TRANSACTION-STATUS PIC X(10). 05 DESCRIPTION PIC X(50). 05 REFERENCE-NUMBER PIC X(20). WORKING-STORAGE SECTION. *> File status variables 01 CUSTOMER-FILE-STATUS PIC X(2). 88 CUSTOMER-FILE-OK VALUE "00". 88 CUSTOMER-EOF VALUE "10". 88 CUSTOMER-NOT-FOUND VALUE "23". 01 TRANSACTION-FILE-STATUS PIC X(2). 88 TRANSACTION-FILE-OK VALUE "00". 88 TRANSACTION-EOF VALUE "10". 88 TRANSACTION-NOT-FOUND VALUE "23". *> Search key structures 01 WS-SEARCH-CRITERIA. 05 WS-SEARCH-NAME PIC X(30). 05 WS-SEARCH-ZIP PIC X(10). 05 WS-SEARCH-PHONE PIC X(15). 05 WS-SEARCH-EMAIL PIC X(40). 05 WS-SEARCH-STATUS PIC X(10). 05 WS-SEARCH-RATING PIC X(5). *> Compound key search structures 01 WS-COMPOUND-SEARCH-KEYS. 05 WS-ACCOUNT-STATUS-KEY. 10 WS-STATUS-SEARCH PIC X(10). 10 WS-RATING-SEARCH PIC X(5). 05 WS-CUSTOMER-TRANS-KEY. 10 WS-CUST-ID-SEARCH PIC X(10). 10 WS-TRANS-DATE-SEARCH PIC X(8). 05 WS-DATE-TYPE-KEY. 10 WS-DATE-SEARCH PIC X(8). 10 WS-TYPE-SEARCH PIC X(10). 05 WS-AMOUNT-RANGE-KEY. 10 WS-AMOUNT-CAT-SEARCH PIC X(5). 10 WS-TRANS-STATUS-SEARCH PIC X(10). *> Processing counters and flags 01 WS-PROCESSING-COUNTERS. 05 WS-RECORDS-READ PIC 9(7) VALUE 0. 05 WS-RECORDS-FOUND PIC 9(7) VALUE 0. 05 WS-DUPLICATE-COUNT PIC 9(5) VALUE 0. 05 WS-SEARCH-COUNT PIC 9(5) VALUE 0. *> Display and formatting variables 01 WS-DISPLAY-FIELDS. 05 WS-FORMATTED-AMOUNT PIC $$$,$$$,$$9.99. 05 WS-FORMATTED-DATE PIC X(2)/X(2)/X(4). 05 WS-FORMATTED-PHONE PIC X(3)-X(3)-X(4). *> Menu and control variables 01 WS-MENU-CONTROL. 05 WS-MENU-CHOICE PIC X(1). 05 WS-CONTINUE-FLAG PIC X(1) VALUE "Y". 88 CONTINUE-PROCESSING VALUE "Y". 88 STOP-PROCESSING VALUE "N". PROCEDURE DIVISION. MAIN-PROCESSING. DISPLAY "=== ALTERNATE Key Demonstration ===". DISPLAY " ". PERFORM OPEN-FILES PERFORM DEMONSTRATE-ALTERNATE-KEY-USAGE PERFORM CLOSE-FILES DISPLAY " ". DISPLAY "ALTERNATE key demonstration completed successfully". STOP RUN. OPEN-FILES. OPEN I-O CUSTOMER-MASTER-FILE. IF NOT CUSTOMER-FILE-OK DISPLAY "Error opening customer file: " CUSTOMER-FILE-STATUS STOP RUN END-IF. OPEN I-O TRANSACTION-FILE. IF NOT TRANSACTION-FILE-OK DISPLAY "Error opening transaction file: " TRANSACTION-FILE-STATUS STOP RUN END-IF. DEMONSTRATE-ALTERNATE-KEY-USAGE. PERFORM UNTIL STOP-PROCESSING PERFORM DISPLAY-MENU PERFORM GET-MENU-CHOICE PERFORM PROCESS-MENU-CHOICE END-PERFORM. DISPLAY-MENU. DISPLAY " ". DISPLAY "ALTERNATE Key Search Options:". DISPLAY "=============================". DISPLAY "1. Search by Customer Name". DISPLAY "2. Search by ZIP Code". DISPLAY "3. Search by Phone Number". DISPLAY "4. Search by Email Address". DISPLAY "5. Search by Account Status and Credit Rating". DISPLAY "6. Search Transactions by Customer and Date". DISPLAY "7. Search Transactions by Date and Type". DISPLAY "8. Search Transactions by Amount Category". DISPLAY "9. Demonstrate Duplicate Key Processing". DISPLAY "0. Exit". DISPLAY " ". GET-MENU-CHOICE. DISPLAY "Enter your choice (0-9): " WITH NO ADVANCING. ACCEPT WS-MENU-CHOICE. PROCESS-MENU-CHOICE. EVALUATE WS-MENU-CHOICE WHEN "1" PERFORM SEARCH-BY-CUSTOMER-NAME WHEN "2" PERFORM SEARCH-BY-ZIP-CODE WHEN "3" PERFORM SEARCH-BY-PHONE WHEN "4" PERFORM SEARCH-BY-EMAIL WHEN "5" PERFORM SEARCH-BY-STATUS-RATING WHEN "6" PERFORM SEARCH-TRANSACTIONS-BY-CUSTOMER-DATE WHEN "7" PERFORM SEARCH-TRANSACTIONS-BY-DATE-TYPE WHEN "8" PERFORM SEARCH-TRANSACTIONS-BY-AMOUNT-CATEGORY WHEN "9" PERFORM DEMONSTRATE-DUPLICATE-PROCESSING WHEN "0" SET STOP-PROCESSING TO TRUE WHEN OTHER DISPLAY "Invalid choice. Please try again." END-EVALUATE. SEARCH-BY-CUSTOMER-NAME. DISPLAY " ". DISPLAY "Search by Customer Name:". DISPLAY "========================". DISPLAY "Enter customer name: " WITH NO ADVANCING. ACCEPT WS-SEARCH-NAME. MOVE WS-SEARCH-NAME TO CUSTOMER-NAME. START CUSTOMER-MASTER-FILE KEY IS EQUAL TO CUSTOMER-NAME INVALID KEY DISPLAY "No customer found with name: " WS-SEARCH-NAME NOT INVALID KEY PERFORM READ-AND-DISPLAY-CUSTOMER END-START. SEARCH-BY-ZIP-CODE. DISPLAY " ". DISPLAY "Search by ZIP Code:". DISPLAY "===================". DISPLAY "Enter ZIP code: " WITH NO ADVANCING. ACCEPT WS-SEARCH-ZIP. MOVE WS-SEARCH-ZIP TO CUSTOMER-ZIP-CODE. START CUSTOMER-MASTER-FILE KEY IS EQUAL TO CUSTOMER-ZIP-CODE INVALID KEY DISPLAY "No customers found in ZIP code: " WS-SEARCH-ZIP NOT INVALID KEY PERFORM READ-ALL-CUSTOMERS-IN-ZIP END-START. SEARCH-BY-PHONE. DISPLAY " ". DISPLAY "Search by Phone Number:". DISPLAY "=======================". DISPLAY "Enter phone number: " WITH NO ADVANCING. ACCEPT WS-SEARCH-PHONE. MOVE WS-SEARCH-PHONE TO CUSTOMER-PHONE. START CUSTOMER-MASTER-FILE KEY IS EQUAL TO CUSTOMER-PHONE INVALID KEY DISPLAY "No customer found with phone: " WS-SEARCH-PHONE NOT INVALID KEY PERFORM READ-AND-DISPLAY-CUSTOMER END-START. SEARCH-BY-EMAIL. DISPLAY " ". DISPLAY "Search by Email Address:". DISPLAY "========================". DISPLAY "Enter email address: " WITH NO ADVANCING. ACCEPT WS-SEARCH-EMAIL. MOVE WS-SEARCH-EMAIL TO CUSTOMER-EMAIL. START CUSTOMER-MASTER-FILE KEY IS EQUAL TO CUSTOMER-EMAIL INVALID KEY DISPLAY "No customer found with email: " WS-SEARCH-EMAIL NOT INVALID KEY PERFORM READ-AND-DISPLAY-CUSTOMER END-START. SEARCH-BY-STATUS-RATING. DISPLAY " ". DISPLAY "Search by Account Status and Credit Rating:". DISPLAY "===========================================". DISPLAY "Enter account status: " WITH NO ADVANCING. ACCEPT WS-STATUS-SEARCH. DISPLAY "Enter credit rating: " WITH NO ADVANCING. ACCEPT WS-RATING-SEARCH. MOVE WS-STATUS-SEARCH TO ACCOUNT-STATUS. MOVE WS-RATING-SEARCH TO CREDIT-RATING. START CUSTOMER-MASTER-FILE KEY IS EQUAL TO ACCOUNT-STATUS-KEY INVALID KEY DISPLAY "No customers found with status: " WS-STATUS-SEARCH " and rating: " WS-RATING-SEARCH NOT INVALID KEY PERFORM READ-ALL-CUSTOMERS-BY-STATUS-RATING END-START. SEARCH-TRANSACTIONS-BY-CUSTOMER-DATE. DISPLAY " ". DISPLAY "Search Transactions by Customer and Date:". DISPLAY "=========================================". DISPLAY "Enter customer ID: " WITH NO ADVANCING. ACCEPT WS-CUST-ID-SEARCH. DISPLAY "Enter transaction date (YYYYMMDD): " WITH NO ADVANCING. ACCEPT WS-TRANS-DATE-SEARCH. MOVE WS-CUST-ID-SEARCH TO CUSTOMER-ID OF TRANSACTION-RECORD. MOVE WS-TRANS-DATE-SEARCH TO TRANSACTION-DATE. START TRANSACTION-FILE KEY IS EQUAL TO CUSTOMER-TRANS-KEY INVALID KEY DISPLAY "No transactions found for customer: " WS-CUST-ID-SEARCH " on date: " WS-TRANS-DATE-SEARCH NOT INVALID KEY PERFORM READ-ALL-CUSTOMER-TRANSACTIONS END-START. SEARCH-TRANSACTIONS-BY-DATE-TYPE. DISPLAY " ". DISPLAY "Search Transactions by Date and Type:". DISPLAY "=====================================". DISPLAY "Enter transaction date (YYYYMMDD): " WITH NO ADVANCING. ACCEPT WS-DATE-SEARCH. DISPLAY "Enter transaction type: " WITH NO ADVANCING. ACCEPT WS-TYPE-SEARCH. MOVE WS-DATE-SEARCH TO TRANSACTION-DATE. MOVE WS-TYPE-SEARCH TO TRANSACTION-TYPE. START TRANSACTION-FILE KEY IS EQUAL TO DATE-TYPE-KEY INVALID KEY DISPLAY "No transactions found for date: " WS-DATE-SEARCH " and type: " WS-TYPE-SEARCH NOT INVALID KEY PERFORM READ-ALL-DATE-TYPE-TRANSACTIONS END-START. SEARCH-TRANSACTIONS-BY-AMOUNT-CATEGORY. DISPLAY " ". DISPLAY "Search Transactions by Amount Category:". DISPLAY "=======================================". DISPLAY "Enter amount category: " WITH NO ADVANCING. ACCEPT WS-AMOUNT-CAT-SEARCH. DISPLAY "Enter transaction status: " WITH NO ADVANCING. ACCEPT WS-TRANS-STATUS-SEARCH. MOVE WS-AMOUNT-CAT-SEARCH TO AMOUNT-CATEGORY. MOVE WS-TRANS-STATUS-SEARCH TO TRANSACTION-STATUS. START TRANSACTION-FILE KEY IS EQUAL TO AMOUNT-RANGE-KEY INVALID KEY DISPLAY "No transactions found for category: " WS-AMOUNT-CAT-SEARCH " and status: " WS-TRANS-STATUS-SEARCH NOT INVALID KEY PERFORM READ-ALL-AMOUNT-CATEGORY-TRANSACTIONS END-START. READ-AND-DISPLAY-CUSTOMER. READ CUSTOMER-MASTER-FILE NEXT RECORD. IF CUSTOMER-FILE-OK PERFORM DISPLAY-CUSTOMER-DETAILS ADD 1 TO WS-RECORDS-FOUND ELSE DISPLAY "Error reading customer record: " CUSTOMER-FILE-STATUS END-IF. READ-ALL-CUSTOMERS-IN-ZIP. MOVE 0 TO WS-DUPLICATE-COUNT. PERFORM UNTIL NOT CUSTOMER-FILE-OK OR CUSTOMER-EOF READ CUSTOMER-MASTER-FILE NEXT RECORD IF CUSTOMER-FILE-OK IF CUSTOMER-ZIP-CODE = WS-SEARCH-ZIP ADD 1 TO WS-DUPLICATE-COUNT PERFORM DISPLAY-CUSTOMER-SUMMARY ELSE SET CUSTOMER-EOF TO TRUE END-IF END-IF END-PERFORM. DISPLAY "Total customers found in ZIP " WS-SEARCH-ZIP ": " WS-DUPLICATE-COUNT. READ-ALL-CUSTOMERS-BY-STATUS-RATING. MOVE 0 TO WS-DUPLICATE-COUNT. PERFORM UNTIL NOT CUSTOMER-FILE-OK OR CUSTOMER-EOF READ CUSTOMER-MASTER-FILE NEXT RECORD IF CUSTOMER-FILE-OK IF ACCOUNT-STATUS = WS-STATUS-SEARCH AND CREDIT-RATING = WS-RATING-SEARCH ADD 1 TO WS-DUPLICATE-COUNT PERFORM DISPLAY-CUSTOMER-SUMMARY ELSE SET CUSTOMER-EOF TO TRUE END-IF END-IF END-PERFORM. DISPLAY "Total customers found with status " WS-STATUS-SEARCH " and rating " WS-RATING-SEARCH ": " WS-DUPLICATE-COUNT. READ-ALL-CUSTOMER-TRANSACTIONS. MOVE 0 TO WS-DUPLICATE-COUNT. PERFORM UNTIL NOT TRANSACTION-FILE-OK OR TRANSACTION-EOF READ TRANSACTION-FILE NEXT RECORD IF TRANSACTION-FILE-OK IF CUSTOMER-ID OF TRANSACTION-RECORD = WS-CUST-ID-SEARCH AND TRANSACTION-DATE = WS-TRANS-DATE-SEARCH ADD 1 TO WS-DUPLICATE-COUNT PERFORM DISPLAY-TRANSACTION-SUMMARY ELSE SET TRANSACTION-EOF TO TRUE END-IF END-IF END-PERFORM. DISPLAY "Total transactions found: " WS-DUPLICATE-COUNT. READ-ALL-DATE-TYPE-TRANSACTIONS. MOVE 0 TO WS-DUPLICATE-COUNT. PERFORM UNTIL NOT TRANSACTION-FILE-OK OR TRANSACTION-EOF READ TRANSACTION-FILE NEXT RECORD IF TRANSACTION-FILE-OK IF TRANSACTION-DATE = WS-DATE-SEARCH AND TRANSACTION-TYPE = WS-TYPE-SEARCH ADD 1 TO WS-DUPLICATE-COUNT PERFORM DISPLAY-TRANSACTION-SUMMARY ELSE SET TRANSACTION-EOF TO TRUE END-IF END-IF END-PERFORM. DISPLAY "Total transactions found: " WS-DUPLICATE-COUNT. READ-ALL-AMOUNT-CATEGORY-TRANSACTIONS. MOVE 0 TO WS-DUPLICATE-COUNT. PERFORM UNTIL NOT TRANSACTION-FILE-OK OR TRANSACTION-EOF READ TRANSACTION-FILE NEXT RECORD IF TRANSACTION-FILE-OK IF AMOUNT-CATEGORY = WS-AMOUNT-CAT-SEARCH AND TRANSACTION-STATUS = WS-TRANS-STATUS-SEARCH ADD 1 TO WS-DUPLICATE-COUNT PERFORM DISPLAY-TRANSACTION-SUMMARY ELSE SET TRANSACTION-EOF TO TRUE END-IF END-IF END-PERFORM. DISPLAY "Total transactions found: " WS-DUPLICATE-COUNT. DISPLAY-CUSTOMER-DETAILS. DISPLAY " ". DISPLAY "Customer Details:". DISPLAY "================". DISPLAY "Customer ID: " CUSTOMER-ID. DISPLAY "Name: " CUSTOMER-NAME. DISPLAY "Address: " CUSTOMER-ADDRESS. DISPLAY "City: " CUSTOMER-CITY ", " CUSTOMER-STATE " " CUSTOMER-ZIP-CODE. MOVE CUSTOMER-PHONE TO WS-FORMATTED-PHONE. DISPLAY "Phone: " WS-FORMATTED-PHONE. DISPLAY "Email: " CUSTOMER-EMAIL. DISPLAY "Account Status: " ACCOUNT-STATUS. DISPLAY "Credit Rating: " CREDIT-RATING. MOVE ACCOUNT-BALANCE TO WS-FORMATTED-AMOUNT. DISPLAY "Account Balance: " WS-FORMATTED-AMOUNT. MOVE LAST-ACTIVITY-DATE TO WS-FORMATTED-DATE. DISPLAY "Last Activity: " WS-FORMATTED-DATE. DISPLAY-CUSTOMER-SUMMARY. DISPLAY CUSTOMER-ID " - " CUSTOMER-NAME " - " CUSTOMER-ZIP-CODE. DISPLAY-TRANSACTION-SUMMARY. MOVE TRANSACTION-AMOUNT TO WS-FORMATTED-AMOUNT. DISPLAY TRANSACTION-ID " - " TRANSACTION-TYPE " - " WS-FORMATTED-AMOUNT. DEMONSTRATE-DUPLICATE-PROCESSING. DISPLAY " ". DISPLAY "Duplicate Key Processing Demonstration:". DISPLAY "======================================". DISPLAY "Processing all customers by ZIP code...". MOVE SPACES TO CUSTOMER-ZIP-CODE. START CUSTOMER-MASTER-FILE KEY IS GREATER THAN CUSTOMER-ZIP-CODE INVALID KEY DISPLAY "No customers found" NOT INVALID KEY PERFORM PROCESS-ALL-ZIP-CODES END-START. PROCESS-ALL-ZIP-CODES. MOVE SPACES TO WS-SEARCH-ZIP. MOVE 0 TO WS-SEARCH-COUNT. PERFORM UNTIL CUSTOMER-EOF READ CUSTOMER-MASTER-FILE NEXT RECORD IF CUSTOMER-FILE-OK IF CUSTOMER-ZIP-CODE NOT = WS-SEARCH-ZIP IF WS-SEARCH-COUNT > 0 DISPLAY "ZIP " WS-SEARCH-ZIP ": " WS-SEARCH-COUNT " customers" END-IF MOVE CUSTOMER-ZIP-CODE TO WS-SEARCH-ZIP MOVE 1 TO WS-SEARCH-COUNT ELSE ADD 1 TO WS-SEARCH-COUNT END-IF END-IF END-PERFORM. IF WS-SEARCH-COUNT > 0 DISPLAY "ZIP " WS-SEARCH-ZIP ": " WS-SEARCH-COUNT " customers" END-IF. CLOSE-FILES. CLOSE CUSTOMER-MASTER-FILE. CLOSE TRANSACTION-FILE.