This document describes how the execution of a statement can be made dependent on a control break, and how control breaks can be used for the evaluation of Natural system functions.
The following topics are covered:
A control break occurs when the value of a control field changes.
The execution of statements can be made dependent on a control break.
A control break can also be used for the evaluation of Natural system functions.
System functions are discussed in System Variables and System Functions. For detailed descriptions of the system functions available, refer to the System Functions documentation.
With the statement AT
BREAK, you specify the processing which is to be performed
whenever a control break occurs, that is, whenever the value of a control field
which you specify with the AT BREAK statement changes. As a
control field, you can use a database field or a user-defined variable.
The following topics are covered below:
The field specified as control field in an
AT BREAK statement is
usually a database field.
Example:
... AT BREAK OF DEPT statements END-BREAK ...
In this example, the control field is the database field
DEPT; if the value of the field changes, for example,
FROM SALE01 to SALE02, the
statements specified in the AT BREAK
statement would be executed.
Instead of an entire field, you can also use only part of a field
as a control field. With the slash-n-slash notation
/n/, you can determine that only the
first n positions of a field are to be checked for a
change in value.
Example:
... AT BREAK OF DEPT /4/ statements END-BREAK ...
In this example, the specified
statements would only be executed if the value of
the first 4 positions of the field DEPT changes, for example, FROM
SALE to TECH; if, however, the field value changes
from SALE01 to SALE02, this would be ignored and no
AT BREAK processing performed.
** Example 'ATBREX01': AT BREAK OF (with database field)
************************************************************************
DEFINE DATA LOCAL
1 MYVIEW VIEW OF EMPLOYEES
2 NAME
2 CITY
2 COUNTRY
2 JOB-TITLE
2 SALARY (1:1)
END-DEFINE
*
READ (5) MYVIEW BY CITY WHERE COUNTRY = 'USA'
DISPLAY CITY (AL=9) NAME 'POSITION' JOB-TITLE 'SALARY' SALARY(1)
/*
AT BREAK OF CITY
WRITE / OLD(CITY) (EM=X^X^X^X^X^X^X^X^X^X^X^)
5X 'AVERAGE:' T*SALARY AVER(SALARY(1)) //
COUNT(SALARY(1)) 'RECORDS FOUND' /
END-BREAK
/*
AT END OF DATA
WRITE 'TOTAL (ALL RECORDS):' T*SALARY(1) TOTAL(SALARY(1))
END-ENDDATA
END-READ
END
In the above program, the first WRITE statement is executed
whenever the value of the field CITY changes.
In the AT
BREAK statement, the Natural system functions
OLD,
AVER and
COUNT are
evaluated (and output in the WRITE statement).
In the AT END OF
DATA statement, the Natural system function
TOTAL is
evaluated.
Output of Program ATBREX01:
Page 1 14-01-14 14:07:26
CITY NAME POSITION SALARY
--------- -------------------- ------------------------- ----------
AIKEN SENKO PROGRAMMER 31500
A I K E N AVERAGE: 31500
1 RECORDS FOUND
ALBUQUERQ HAMMOND SECRETARY 22000
ALBUQUERQ ROLLING MANAGER 34000
ALBUQUERQ FREEMAN MANAGER 34000
ALBUQUERQ LINCOLN ANALYST 41000
A L B U Q U E R Q U E AVERAGE: 32750
4 RECORDS FOUND
TOTAL (ALL RECORDS): 162500
A user-defined variable
can also be used as control field in an AT BREAK statement.
In the following program, the user-defined variable
#LOCATION is used as control field.
** Example 'ATBREX02': AT BREAK OF (with user-defined variable and
** in conjunction with BEFORE BREAK PROCESSING)
************************************************************************
DEFINE DATA LOCAL
1 MYVIEW VIEW OF EMPLOYEES
2 CITY
2 COUNTRY
2 JOB-TITLE
2 SALARY (1:1)
*
1 #LOCATION (A20)
END-DEFINE
*
READ (5) MYVIEW BY CITY WHERE COUNTRY = 'USA'
BEFORE BREAK PROCESSING
COMPRESS CITY 'USA' INTO #LOCATION
END-BEFORE
DISPLAY #LOCATION 'POSITION' JOB-TITLE 'SALARY' SALARY (1)
/*
AT BREAK OF #LOCATION
SKIP 1
END-BREAK
END-READ
END
Output of Program ATBREX02:
Page 1 14-01-14 14:08:36
#LOCATION POSITION SALARY
-------------------- ------------------------- ----------
AIKEN USA PROGRAMMER 31500
ALBUQUERQUE USA SECRETARY 22000
ALBUQUERQUE USA MANAGER 34000
ALBUQUERQUE USA MANAGER 34000
ALBUQUERQUE USA ANALYST 41000
As explained
above,
the notation /n/ allows some portion of
a field to be checked for a control break. It is possible to combine several
AT BREAK statements,
using an entire field as control field for one break and part of the same field
as control field for another break.
In such a case, the break at the lower level (entire field) must
be specified before the break at the higher level (part of field); that is, in
the first AT BREAK statement the entire field must be specified as
control field, and in the second one part of the field.
The following example program illustrates this, using the field
DEPT as well as the first 4 positions of that field (DEPT
/4/).
** Example 'ATBREX03': AT BREAK OF (two statements in combination)
************************************************************************
DEFINE DATA LOCAL
1 MYVIEW VIEW OF EMPLOYEES
2 NAME
2 JOB-TITLE
2 DEPT
2 SALARY (1:1)
2 CURR-CODE (1:1)
END-DEFINE
*
READ MYVIEW BY DEPT STARTING FROM 'SALE40' ENDING AT 'TECH10'
WHERE SALARY(1) GT 47000 AND CURR-CODE(1) = 'USD'
/*
AT BREAK OF DEPT
WRITE '*** LOWEST BREAK LEVEL ***' /
END-BREAK
AT BREAK OF DEPT /4/
WRITE '*** HIGHEST BREAK LEVEL ***'
END-BREAK
/*
DISPLAY DEPT NAME 'POSITION' JOB-TITLE
END-READ
END
Output of Program ATBREX03:
Page 1 14-01-14 14:09:20
DEPARTMENT NAME POSITION
CODE
---------- -------------------- -------------------------
TECH05 HERZOG MANAGER
TECH05 LAWLER MANAGER
TECH05 MEYER MANAGER
*** LOWEST BREAK LEVEL ***
TECH10 DEKKER DBA
*** LOWEST BREAK LEVEL ***
*** HIGHEST BREAK LEVEL ***
In the following program, one blank line is output whenever the
value of the field DEPT changes; and whenever the value in the
first 4 positions of DEPT changes, a record count is carried out
by evaluating the system function COUNT.
** Example 'ATBREX04': AT BREAK OF (two statements in combination)
************************************************************************
DEFINE DATA LOCAL
1 MYVIEW VIEW OF EMPLOYEES
2 DEPT
2 REDEFINE DEPT
3 #GENDEP (A4)
2 NAME
2 SALARY (1)
END-DEFINE
*
WRITE TITLE '** PERSONS WITH SALARY > 30000, SORTED BY DEPARTMENT **' /
LIMIT 9
READ MYVIEW BY DEPT FROM 'A' WHERE SALARY(1) > 30000
DISPLAY 'DEPT' DEPT NAME 'SALARY' SALARY(1)
/*
AT BREAK OF DEPT
SKIP 1
END-BREAK
AT BREAK OF DEPT /4/
WRITE COUNT(SALARY(1)) 'RECORDS FOUND IN:' OLD(#GENDEP) /
END-BREAK
END-READ
END
Output of Program ATBREX04:
** PERSONS WITH SALARY > 30000, SORTED BY DEPARTMENT **
DEPT NAME SALARY
------ -------------------- ----------
ADMA01 JENSEN 180000
ADMA01 PETERSEN 105000
ADMA01 MORTENSEN 320000
ADMA01 MADSEN 149000
ADMA01 BUHL 642000
ADMA02 HERMANSEN 391500
ADMA02 PLOUG 162900
ADMA02 HANSEN 234000
8 RECORDS FOUND IN: ADMA
COMP01 HEURTEBISE 168800
1 RECORDS FOUND IN: COMP
Automatic break processing is in effect for a processing loop which
contains an AT BREAK
statement. This applies to the following statements:
The value of the control field specified with the
AT BREAK statement is
checked only for records which satisfy the selection criteria of both the
WITH clause
and the WHERE clause.
Natural system
functions (AVER,
MAX,
MIN,
etc.) are evaluated for each record after all statements within the processing
loop have been executed. System functions are not evaluated for any record
which is rejected by WHERE criteria.
The figure below illustrates the flow logic of automatic break processing.

The following example shows the use of the
Natural system functions
OLD,
MIN,
AVER,
MAX,
SUM and
COUNT in an
AT BREAK statement
(and of the system function TOTAL in an
AT END OF DATA
statement).
** Example 'ATBREX05': AT BREAK OF (with system functions)
************************************************************************
DEFINE DATA LOCAL
1 MYVIEW VIEW OF EMPLOYEES
2 NAME
2 CITY
2 SALARY (1:1)
2 CURR-CODE (1:1)
END-DEFINE
*
LIMIT 3
READ MYVIEW BY CITY = 'SALT LAKE CITY'
DISPLAY NOTITLE CITY NAME 'SALARY' SALARY(1) 'CURRENCY' CURR-CODE(1)
/*
AT BREAK OF CITY
WRITE / OLD(CITY) (EM=X^X^X^X^X^X^X^X^X^X^X^X^X^X^X)
31T ' - MINIMUM:' MIN(SALARY(1)) CURR-CODE(1) /
31T ' - AVERAGE:' AVER(SALARY(1)) CURR-CODE(1) /
31T ' - MAXIMUM:' MAX(SALARY(1)) CURR-CODE(1) /
31T ' - SUM:' SUM(SALARY(1)) CURR-CODE(1) /
33T COUNT(SALARY(1)) 'RECORDS FOUND' /
END-BREAK
/*
AT END OF DATA
WRITE 22T 'TOTAL (ALL RECORDS):'
T*SALARY TOTAL(SALARY(1)) CURR-CODE(1)
END-ENDDATA
END-READ
END
Output of Program ATBREX05:
CITY NAME SALARY CURRENCY
-------------------- -------------------- ---------- --------
SALT LAKE CITY ANDERSON 50000 USD
SALT LAKE CITY SAMUELSON 24000 USD
S A L T L A K E C I T Y - MINIMUM: 24000 USD
- AVERAGE: 37000 USD
- MAXIMUM: 50000 USD
- SUM: 74000 USD
2 RECORDS FOUND
SAN DIEGO GEE 60000 USD
S A N D I E G O - MINIMUM: 60000 USD
- AVERAGE: 60000 USD
- MAXIMUM: 60000 USD
- SUM: 60000 USD
1 RECORDS FOUND
TOTAL (ALL RECORDS): 134000 USD
See the following example program:
With the BEFORE BREAK
PROCESSING statement, you can specify statements that are to
be executed immediately before a control break; that is, before the value of
the control field is checked, before the statements specified in the
AT BREAK block are
executed, and before any Natural system
functions are evaluated.
** Example 'BEFORX01': BEFORE BREAK PROCESSING
************************************************************************
DEFINE DATA LOCAL
1 MYVIEW VIEW OF EMPLOYEES
2 NAME
2 FIRST-NAME
2 SALARY (1:1)
2 BONUS (1:1,1:1)
*
1 #INCOME (P11)
END-DEFINE
*
LIMIT 5
READ MYVIEW BY NAME FROM 'B'
BEFORE BREAK PROCESSING
COMPUTE #INCOME = SALARY(1) + BONUS(1,1)
END-BEFORE
/*
DISPLAY NOTITLE NAME FIRST-NAME (AL=10)
'ANNUAL/INCOME' #INCOME 'SALARY' SALARY(1) (LC==) /
'+ BONUS' BONUS(1,1) (IC=+)
AT BREAK OF #INCOME
WRITE T*#INCOME '-'(24)
END-BREAK
END-READ
END
Output of Program BEFORX01:
NAME FIRST-NAME ANNUAL SALARY
INCOME + BONUS
-------------------- ---------- ------------ -----------
BACHMANN HANS 56800 = 52800
+4000
------------------------
BAECKER JOHANNES 81000 = 74400
+6600
------------------------
BAECKER KARL 52650 = 48600
+4050
------------------------
BAGAZJA MARJAN 152700 = 129700
+23000
------------------------
BAILLET PATRICK 198500 = 188000
+10500
------------------------
With automatic break processing, the statements specified in an
AT BREAK block are
executed whenever the value of the specified control field changes - regardless
of the position of the AT BREAK statement in the processing
loop.
With a PERFORM BREAK
PROCESSING statement, you can perform break processing at a
specified position in a processing loop: the PERFORM BREAK
PROCESSING statement is executed when it is encountered in the
processing flow of the program.
Immediately after the PERFORM BREAK PROCESSING, you
specify one or more AT BREAK statement blocks:
...
PERFORM BREAK PROCESSING
AT BREAK OF field1
statements
END-BREAK
AT BREAK OF field2
statements
END-BREAK
...
When a PERFORM BREAK PROCESSING is executed, Natural
checks if a break has occurred; that is, if the value of the specified control
field has changed; and if it has, the specified statements are executed.
With PERFORM BREAK PROCESSING, system functions are
evaluated before Natural checks if a break has occurred.
The following figure illustrates the flow logic of user-initiated break processing:

** Example 'PERFBX01': PERFORM BREAK PROCESSING (with BREAK option
** in IF statement)
************************************************************************
DEFINE DATA LOCAL
1 MYVIEW VIEW OF EMPLOYEES
2 NAME
2 DEPT
2 SALARY (1:1)
*
1 #CNTL (N2)
END-DEFINE
*
LIMIT 7
READ MYVIEW BY DEPT
AT BREAK OF DEPT /* <- automatic break processing
SKIP 1
WRITE 'SUMMARY FOR ALL SALARIES '
'SUM:' SUM(SALARY(1))
'TOTAL:' TOTAL(SALARY(1))
ADD 1 TO #CNTL
END-BREAK
/*
IF SALARY (1) GREATER THAN 100000 OR BREAK #CNTL
PERFORM BREAK PROCESSING /* <- user-initiated break processing
AT BREAK OF #CNTL
WRITE 'SUMMARY FOR SALARY GREATER 100000'
'SUM:' SUM(SALARY(1))
'TOTAL:' TOTAL(SALARY(1))
END-BREAK
END-IF
/*
IF SALARY (1) GREATER THAN 150000 OR BREAK #CNTL
PERFORM BREAK PROCESSING /* <- user-initiated break processing
AT BREAK OF #CNTL
WRITE 'SUMMARY FOR SALARY GREATER 150000'
'SUM:' SUM(SALARY(1))
'TOTAL:' TOTAL(SALARY(1))
END-BREAK
END-IF
DISPLAY NAME DEPT SALARY(1)
END-READ
END
Output of Program PERFBX01:
Page 1 14-01-14 14:13:35
NAME DEPARTMENT ANNUAL
CODE SALARY
-------------------- ---------- ----------
JENSEN ADMA01 180000
PETERSEN ADMA01 105000
MORTENSEN ADMA01 320000
MADSEN ADMA01 149000
BUHL ADMA01 642000
SUMMARY FOR ALL SALARIES SUM: 1396000 TOTAL: 1396000
SUMMARY FOR SALARY GREATER 100000 SUM: 1396000 TOTAL: 1396000
SUMMARY FOR SALARY GREATER 150000 SUM: 1142000 TOTAL: 1142000
HERMANSEN ADMA02 391500
PLOUG ADMA02 162900
SUMMARY FOR ALL SALARIES SUM: 554400 TOTAL: 1950400
SUMMARY FOR SALARY GREATER 100000 SUM: 554400 TOTAL: 1950400
SUMMARY FOR SALARY GREATER 150000 SUM: 554400 TOTAL: 1696400