Was this helpful?
The Department-Employee Master/Detail Application
This application uses two database tables joined on a specific column. This typical example of a department and its employees demonstrates how to process two tables as a master and a detail.
The program scans through all the departments in a database table, in order to reduce expenses. Based on certain criteria, the program updates department and employee records. The conditions for updating the data are the following:
Departments:
If a department has made less than $50,000 in sales, the department is dissolved.
Employees:
If an employee was hired since the start of 1985, the employee is terminated.
If the employee's yearly salary is more than the minimum company wage of $14,000 and the employee is not nearing retirement (over 58 years of age), the employee takes a 5% pay cut.
If the employee's department is dissolved and the employee is not terminated, the employee is moved into a state of limbo to be resolved by a supervisor.
This program uses two cursors in a master/detail fashion. The first cursor is for the Department table, and the second cursor is for the Employee table. Both tables are described in declare table statements at the start of the program. The cursors retrieve all the information in the tables, some of which is updated. The cursor for the Employee table also retrieves an integer date interval whose value is positive if the employee was hired after January 1, 1985. The tables contain no null values.
Each row that is scanned, from both the Department table and the Employee table, is recorded into the system output file. This file serves both as a log of the session and as a simplified report of the updates that were made.
Each section of code is commented for the purpose of the application and also to clarify some of the uses of the Embedded SQL statements. The program illustrates table creation, multi‑statement transactions, all cursor statements, direct updates and error handling.
IDENTIFICATION DIVISION.
PROGRAM-ID. EXPENSE-PROCESS.
ENVIRONMENT DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
        EXEC SQL INCLUDE SQLCA END-EXEC.
        EXEC SQL BEGIN DECLARE SECTION END-EXEC.
*       The department table
        EXEC SQL DECLARE dept TABLE
            (name         char(12)       NOT NULL,
             totsales     decimal(9,2)   NOT NULL,
             employees    smallint       NOT NULL)
        END-EXEC.
*       The employee table
        EXEC SQL DECLARE employee TABLE
            (name            char(20)     NOT NULL,
             age             integer1     NOT NULL,
             idno            integer      NOT NULL,
             hired           date         NOT NULL,
             dept            char(12)     NOT NULL,
             salary          decimal(8,2) NOT NULL)
        END-EXEC.
*       "State-of-Limbo" for employees who lose their department
        EXEC SQL DECLARE toberesolved TABLE
           (name             char(20)     NOT NULL,
            age              integer1     NOT NULL,
            idno             integer      NOT NULL,
            hired            date         NOT NULL,
            dept             char(12)     NOT NULL,
            salary           decimal(8,2) NOT NULL)
        END-EXEC.
*      Minimum sales of department
       01    MIN-DEPT-SALES    PIC S9(5)V9(2) USAGE COMP
                                VALUE IS 50000.00.
*      Minimum employee salary
       01    MIN-EMP-SALARY    PIC S9(5)V9(2) USAGE COMP
                                VALUE IS 14000.00.
*      Age above which no salary-reduction will be made
       01    NEARLY-RETIRED    PIC S9(2) USAGE COMP
                                        VALUE IS 58.
*      Salary-reduction percentage
       01   SALARY-REDUC    PIC S9(1)V9(2) USAGE COMP
                                       VALUE IS 0.95.
*      Record corresponding to the "dept" table.
       01      DEPT.
               02 DNAME         PIC X(12).
               02 TOTSALES      PIC S9(7)V9(2) USAGE COMP.
               02 EMPLOYEES     PIC S9(4) USAGE COMP.
*      Record corresponding to the "employee" table
       01      EMP.
                02 ENAME          PIC X(20).
                02 AGE            PIC S9(2) USAGE COMP.
                02 IDNO           PIC S9(8) USAGE COMP.
                02 HIRED          PIC X(26).
                02 SALARY         PIC S9(6)V9(2) USAGE COMP.
                02 HIRED-SINCE-85 PIC S9(4) USAGE COMP.
*      Count of employees terminated.
       01      EMPS-TERM          PIC S99 USAGE COMP.
*      Indicates whether the employee's dept was deleted
       01      DELETED-DEPT       PIC S9 USAGE COMP.
*      Error message buffer used by CHECK-ERRORS.
       01     ERRBUF              PIC X(200).
*      Formatting values for output
       01      DEPT-OUT.
                02 FILLER        PIC X(12) VALUE "Department: ".
                02 DNAME-OUT     PIC X(12).
                02 FILLER        PIC X(13) VALUE "Total Sales: ".
                02 TOTSALES-OUT  PIC $,$$$,$$9.9(2) USAGE DISPLAY.
                02 DEPT-FORMAT   PIC X(19).
       01      EMP-OUT.
                02 FILLER          PIC XX VALUE SPACES.
                02 TITLE           PIC X(11).
                02 IDNO-OUT        PIC Z9(6) USAGE DISPLAY.
                02 FILLER          PIC X VALUE SPACE.
                02 ENAME-OUT       PIC X(20).
                02 AGE-OUT         PIC Z9(2) USAGE DISPLAY.
                02 FILLER          PIC XX VALUE SPACES.
                02 SALARY-OUT      PIC $$$,$$9.9(2) USAGE DISPLAY.
                02 FILLER          PIC XX VALUE SPACES.
                02 DESCRIPTION      PIC X(24).
       EXEC SQL END DECLARE SECTION END-EXEC.
**
* Procedure Division
*
*     Initialize the database, process each department and
*     terminate the session.
**
      PROCEDURE DIVISION.
      EXAMPLE SECTION.
      XBEGIN.
      DISPLAY "Entering application to process expenses".
      PERFORM INIT-DB THRU END-INITDB.
      PERFORM PROCESS-DEPTS THRU END-PROCDEPTS.
      PERFORM END-DB THRU END-ENDDB.
      DISPLAY "Successful completion of application".
      STOP RUN.
**
* Paragraph: INIT-DB
*
*     Start up the database, and abort if there is an error
*     Before processing employees, create the table for employees
*     who lose their department, "toberesolved".
**
      INIT-DB.
      EXEC SQL WHENEVER SQLERROR STOP END-EXEC.
      EXEC SQL CONNECT personnel END-EXEC.
      DISPLAY "Creating ""To_Be_Resolved"" table".
      EXEC SQL CREATE TABLE toberesolved
                (name     char(20),
                 age      integer1,
                 idno     integer,
                 hired    date,
                 dept     char(12),
                 salary   decimal(8,2)
      END-EXEC.
      END-INITDB.
      EXIT.
**
* Paragraph: END-DB
*
*     Commit the multi-statement transaction and close access to
*     the database after successful completion of the application.
**
      END-DB.
      EXEC SQL COMMIT END-EXEC.
      EXEC SQL DISCONNECT END-EXEC.
      END-ENDDB.
      EXIT.
**
* Paragraph: PROCESS-DEPTS
*
*    Scan through all the departments, processing each one.
*    If the department has made less than $50,000 in sales, then
*    the department is dissolved. For each department process
*    all the employees (they may even be moved to another table).
*    If an employee was terminated, then update the department's
*    employee counter.
**
      PROCESS-DEPTS.
      EXEC SQL DECLARE deptcsr CURSOR FOR
              SELECT name, totsales, employees
              FROM dept
              FOR DIRECT UPDATE OF name, employees
              END-EXEC.
*     All errors from this point on close down the application.
      EXEC SQL WHENEVER SQLERROR GOTO CLOSE-DOWN END-EXEC.
      EXEC SQL WHENEVER NOT FOUND GOTO CLOSE-DEPT-CSR END-EXEC.
      EXEC SQL OPEN deptcsr END-EXEC.
      PERFORM UNTIL SQLCODE NOT = 0
           EXEC SQL FETCH deptcsr INTO :DEPT END-EXEC
*          Did the department reach minimum sales?
           IF TOTSALES < MIN-DEPT-SALES THEN
                  EXEC SQL DELETE FROM dept
                       WHERE CURRENT OF deptcsr END-EXEC
                  MOVE 1 TO DELETED-DEPT
                  MOVE " -- DISSOLVED --" TO DEPT-FORMAT
           ELSE
                  MOVE 0 TO DELETED-DEPT
                  MOVE SPACES TO DEPT-FORMAT
           END-IF
*          Log what we have just done
           MOVE DNAME    TO DNAME-OUT
           MOVE TOTSALES TO TOTSALES-OUT
           DISPLAY DEPT-OUT
*          Now process each employee in the department
           PERFORM PROCESS-EMPLOYEES THRU END-PROCEMPLOYEES
*          If some employees were terminated, record this fact
           IF EMPS-TERM > 0 AND DELETED-DEPT = 0 THEN
                EXEC SQL UPDATE dept
                      SET employees = :EMPLOYEES - :EMPS-TERM
                      WHERE CURRENT OF deptcsr END-EXEC
           END-IF
        END-PERFORM.
        
        CLOSE-DEPT-CSR.
            EXEC SQL WHENEVER NOT FOUND CONTINUE END-EXEC.
            EXEC SQL CLOSE deptcsr END-EXEC.
            END-PROCDEPTS.
            EXIT.
**
* Paragraph: PROCESS-EMPLOYEES
*
*    Scan through all the employees for a particular department.
*    Based on given conditions the employee may be terminated, or
*    given a salary reduction:
*      1.  If an employee was hired since 1985 then the employe
*          is terminated.
*      2.  If the employee's yearly salary is more than the
*          minimum company wage of $14,000 and the employee is
*          not close to retirement (over 58 years of age), then 
*          the employee takes a 5% salary reduction.
*      3.  If the employee's department is dissolved and the
*          employee is not terminated, then the employee is moved
*          into the "toberesolved" table.
**
       PROCESS-EMPLOYEES.
*      Note the use of the Ingres functions to find out
*      who was hired since 1985.
       EXEC SQL DECLARE empcsr CURSOR FOR
                  SELECT name, age, idno, hired, salary,
                    int4(interval('days', hired - 
date('01-jan-1985')))
                  FROM employee
                  WHERE dept = :DNAME
                  FOR DIRECT UPDATE OF name, salary
                  END-EXEC.
*      All errors from this point on close down the application.
       EXEC SQL WHENEVER SQLERROR GOTO CLOSE-DOWN END-EXEC.
       EXEC SQL WHENEVER NOT FOUND GOTO CLOSE-EMP-CSR END-EXEC.
       EXEC SQL OPEN empcsr END-EXEC.
*      Record how many employees are terminated
       MOVE 0 TO EMPS-TERM.
       PERFORM UNTIL SQLCODE NOT = 0
            EXEC SQL FETCH empcsr INTO :EMP END-EXEC
            IF HIRED-SINCE-85 > 0 THEN
                  EXEC SQL DELETE FROM employee
                      WHERE CURRENT OF empcsr END-EXEC
                  MOVE "Terminated:" TO TITLE
                  MOVE "Reason: Hired since 1985." TO DESCRIPTION
                  ADD 1 TO EMPS-TERM
            ELSE
*                 Reduce salary if not nearly retired
                  IF SALARY > MIN-EMP-SALARY THEN
                      IF AGE < NEARLY-RETIRED THEN
                          EXEC SQL UPDATE employee
                              SET salary = salary * :SALARY-REDUC
                              WHERE CURRENT OF empcsr END-EXEC
                          MOVE "Reduction: " TO TITLE
                          MOVE "Reason: Salary." TO DESCRIPTION
                      ELSE
*                         Do not reduce salary
                          MOVE "No Changes:" TO TITLE
                          MOVE "Reason: Retiring." TO DESCRIPTION
                      END-IF
*                 Leave employee alone
                  ELSE
                      MOVE "No Changes:" TO TITLE
                      MOVE "Reason: Salary." TO DESCRIPTION
                  END-IF
*                 Was employee's department dissolved?
                  IF DELETED-DEPT = 1 THEN
                      EXEC SQL INSERT INTO toberesolved
                          SELECT * FROM employee
                          WHERE idno = :IDNO END-EXEC
                      EXEC SQL DELETE FROM employee
                          WHERE CURRENT OF empcsr END-EXEC
                  END-IF
            END-IF
*           Log the employee's information
            MOVE IDNO    TO IDNO-OUT
            MOVE ENAME   TO ENAME-OUT
            MOVE AGE     TO AGE-OUT
            MOVE SALARY  TO SALARY-OUT
            DISPLAY EMP-OUT
        END-PERFORM.
CLOSE-EMP-CSR.
      EXEC SQL WHENEVER NOT FOUND CONTINUE END-EXEC
      EXEC SQL CLOSE empcsr END-EXEC.
END-PROCEMPLOYEES.
      EXIT.
**
* Paragraph: CLOSE-DOWN
*
*    This paragraph serves as an error handler called any time
*    after INIT-DB has successfully completed. In all cases, it
*    prints the cause of the error, and aborts the transaction,
*    backing ou changes. Note that disconnecting from the
*    database will implicitly close any open cursors too.
**
CLOSE-DOWN.
*     Turn off error handling
      EXEC SQL WHENEVER SQLERROR CONTINUE END-EXEC.
      EXEC SQL INQUIRE_SQL(:ERRBUF = ERRORTEXT) END-EXEC.
      DISPLAY "Closing Down because of database error:".
      DISPLAY ERRBUF.
      EXEC SQL ROLLBACK END-EXEC.
      EXEC SQL DISCONNECT END-EXEC.
      STOP RUN. 
Last modified date: 04/03/2024