Using Break Logic

This chapter provides an overview of break logic and discusses how to:

Click to jump to parent topicUnderstanding Break Logic

A break is a change in the value of a column or variable. Records with the same value—for example, records with the same value for state—logically belong to a group. When a break occurs, a new group begins.

Use break logic in a report to:

For example, you can use break logic to prepare a sales report with records that are grouped by product, region, or salesperson (or all three). Break logic also enables you to print column headings, count records, subtotal a column, and perform additional processing on the count or subtotal.

Here is the sample program without break logic:

Program ex5a.sqr begin-program do list_customers end-program begin-heading 2 print 'State' (1,1) print 'City' (1,7) print 'Name' (1,24) print 'Phone' (1,55) end-heading begin-procedure list_customers begin-select state (,1) city (,7) name (,24) phone (,55) position (+1) ! Advance to the next line from customers order by state, city, name end-select end-procedure ! list_customers

The output for the ex4a.sqr program is:

State City Name Phone IN Davenport Harold Alexander Fink 3015553645 IN Miningville Harry's Landmark Diner 3175550948 MI Bell Harbor Sam Johnson 3135556732 NH Frogline Jerry's Junkyard Specialties 6125552877 NJ Teaneck Clair Butterfield 2015559901 NM Big Falls Joe Smith and Company 8085552124 NY Mamaroneck Harriet Bailey 9145550144 NY New York John Conway 2125552311 NY New York Corks and Bottles, Inc. 2125550021 NY New York Kate's Out of Date Dress Shop 2125559000 NY Queens Eliot Richards 2125554285 OH Cleveland Quentin Fields 2165553341 OH Everretsville Gregory Stonehaven 2165553109 OH Zanesville Isaiah J Schwartz and Company 5185559813

When you sort the output by state, city, and name (note the ORDER BY clause in the BEGIN-SELECT), the records are grouped by state. To make the grouping more apparent, you can add a break.

Click to jump to parent topicUsing ON-BREAK

In the following program, the ON-BREAK option of the PRINT command accomplishes two related tasks: it starts a new group each time the value of state changes, and it prints state only when its value changes. Note that ON-BREAK works as well for implicit as for explicit PRINT commands, such as in the following example, where state, city, name, and phone are implicitly printed as part of the select paragraph.

The sample program here is identical to ex5a.sqr except for the line that prints the state column, which appears like this:

Program ex5b.sqr begin-program do list_customers end-program begin-heading 2 print 'State' (1,1) print 'City' (1,7) print 'Name' (1,24) print 'Phone' (1,55) end-heading begin-procedure list_customers begin-select ​state (,1) on-break ​city (,7) name (,24) phone (,55) position (+1) ! Advance to the next line from customers order by state, city, name end-select end-procedure ! list_customers

The output for the ex5b.sqr program is:

State City Name Phone IN Davenport Harold Alexander Fink 3015553645 Miningville Harry's Landmark Diner 3175550948 MI Bell Harbor Sam Johnson 3135556732 NH Frogline Jerry's Junkyard Specialties 6125552877 NJ Teaneck Clair Butterfield 2015559901 NM Big Falls Joe Smith and Company 8085552124 NY Mamaroneck Harriet Bailey 9145550144 New York John Conway 2125552311 New York Corks and Bottles, Inc. 2125550021 New York Kate's Out of Date Dress Shop 2125559000 Queens Eliot Richards 2125554285 OH Cleveland Quentin Fields 2165553341 Everretsville Gregory Stonehaven 2165553109 Zanesville Isaiah J Schwartz and Company 5185559813

With break processing, the state abbreviation is printed only once for each group.

Click to jump to parent topicSkipping Lines Between Groups

You can further enhance the visual effect of break processing by inserting one or more lines between groups. To do so, use the SKIPLINES qualifier with ON-BREAK. Here is the list_customers procedure from ex5b.sqr, with the modified line shown like this:

begin-select ​state (,1) on-break skiplines=1 ​city (,7) name (,24) phone (,55) position (+1) ! Advance to the next line from customers order by state, city, name end-select

The output for the modified ex5b.sqr program is:

State City Name Phone IN Davenport Harold Alexander Fink 3015553645 Miningville Harry's Landmark Diner 3175550948 MI Bell Harbor Sam Johnson 3135556732 NH Frogline Jerry's Junkyard Specialties 6125552877 .....

Click to jump to parent topicArranging Multiple Break Columns

As you can see in the previous example, you can also have multiple customers within a city. You can apply the same break concept to the city column to make this grouping of customers more apparent. Add another ON-BREAK to the program so that city is also printed only when its value changes.

When you have multiple breaks, you must arrange them in a hierarchy. In the sample program, the breaks are for geographical units, so arranging them according to size is logical: first state, then city. This sort of arrangement is called nesting, and the breaks are considered nested.

To ensure that the breaks are properly nested, use the LEVEL keyword. This argument numbers breaks by level and specifies that the columns are printed in order of increasing break levels, from left to right. Number breaks in the same order in which they are sorted in the ORDER BY clause.

See Understanding the Order of Events.

The LEVEL argument enables you to control the order in which you call break procedures. The next sample program is identical to ex5a.sqr except for the two lines that print the state and city columns, which are shown like this:

Program ex5c.sqr begin-program do list_customers end-program begin-heading 2 print 'State' (1,1) print 'City' (1,7) print 'Name' (1,24) print 'Phone' (1,55) end-heading begin-procedure list_customers begin-select ​state (,1) on-break level=1 city (,7) on-break level=2 ​name (,24) phone (,55) position (+1) ! Advance to the next line from customers order by state, city, name end-select end-procedure ! list_customers

The output for the ex5c.sqr program is:

State City Name Phone IN Davenport Harold Alexander Fink 3015553645 Miningville Harry's Landmark Diner 3175550948 MI Bell Harbor Sam Johnson 3135556732 NH Frogline Jerry's Junkyard Specialties 6125552877 NJ Teaneck Clair Butterfield 2015559901 NM Big Falls Joe Smith and Company 8085552124 NY Mamaroneck Harriet Bailey 9145550144 New York John Conway 2125552311 Corks and Bottles, Inc. 2125550021 Kate's Out of Date Dress Shop 2125559000 Queens Eliot Richards 2125554285 OH Cleveland Quentin Fields 2165553341 Everretsville Gregory Stonehaven 2165553109 Zanesville Isaiah J Schwartz and Company 5185559813

As you can see, three customers are in New York, so the city name for the second and third customers is left blank.

Click to jump to parent topicUsing Break Processing Enhancements

This section discusses how to:

Click to jump to top of pageClick to jump to parent topicControlling Page Breaks and Calculating Subtotals and Totals

When you use break logic, you may want to enhance your report by controlling page breaks or calculating subtotals and totals for the ON-BREAK column. The following example illustrates these techniques.

The sample program selects the customer's name, address, and telephone number from the database. The break processing is performed on the state column:

Program ex5d.sqr begin-program do list_customers end-program begin-heading 4 print 'Customers Listed by State' (1) center print $current-date (1,1) Edit 'DD-Mon-YYYY' print 'State' (3,1) print 'Customer Name, Address and Phone Number' (,11) print '-' (4,1,9) fill print '-' (4,11,40) fill end-heading begin-footing 2 ! print "Page n of m" page-number (1,1) 'Page ' last-page () ' of ' end-footing begin-procedure state_tot print ' Total Customers for State: ' (+1,1) print #state_total () edit 999,999 position (+3,1) ! Leave 2 blank lines. let #cust_total = #cust_total + #state_total let #state_total = 0 end-procedure ! state_tot begin-procedure list_customers let #state_total = 0 let #cust_total = 0 begin-select ! The 'state' field will only be printed when it ! changes. The procedure 'state_tot' will also be ! executed only when the value of 'state' changes. state (,1) on-break print=change/top-page after=state_tot name (,11) addr1 (+1,11) ! continue on second line addr2 (+1,11) ! continue on third line city (+1,11) ! continue on fourth line phone (,+2) edit (xxx)bxxx-xxxx ! Edit for easy reading. ! Skip 1 line between listings. ! Since each listing takes 4 lines, we specify 'need=4' to ! prevent a customer's data from being broken across two pages. next-listing skiplines=1 need=4 let #state_total = #state_total + 1 from customers order by state, name end-select if #cust_total > 0 print ' Total Customers: ' (+3,1) print #cust_total () edit 999,999 ! Total customers printed. else print 'No customers.' (1,1) end-if end-procedure ! list_customers

The output for the ex5d.sqr program is:

29-Apr-2004 Customers Listed by State State Customer Name, Address and Phone Number --------- ---------------------------------------- IN Harold Alexander Fink 32077 Cedar Street West End Davenport (301) 555-3645 Harry's Landmark Diner 17043 Silverfish Road South Park Miningville (317) 555-0948 Total Customers for State: 2 MI Sam Johnson 37 Cleaver Street Sandy Acres Bell Harbor (313) 555-6732 Total Customers for State: 1 NH Jerry's Junkyard Specialties Crazy Lakes Cottages Rural Delivery #27 Frogline (612) 555-2877 Total Customers for State: 1 ...

Take a close look at the code. The data is printed by using a select paragraph in the list_customer procedure. The state and the customer name are printed on the first line. The customer's address and phone number are printed on the next three lines.

The program also uses the argument AFTER=STATE_TOT. This argument calls the state_tot procedure after each change in the value of state.

See Setting Break Procedures with BEFORE and AFTER.

Click to jump to top of pageClick to jump to parent topicHandling Page Breaks

If a page break occurs within a group, you may want to reprint headings and the value of the break column at the top of the new page.

To control the printing of the value, use PRINT=CHANGE/TOP-PAGE. With this qualifier, the value of the ON-BREAK column is printed when it changes and after every page break. In this example, the value of state is printed not only when it changes, but whenever the report starts a new page.

To format records, use the NEXT-LISTING command. This command serves two purposes. The SKIPLINES=1 argument skips one line between records, then renumbers the current line as line 1. The NEED=4 argument prevents a listing from being split over two pages by specifying the minimum number of lines that are needed to write a new listing on the current page. In this case, if fewer than four lines are left on a page, SQR starts a new page.

Click to jump to top of pageClick to jump to parent topicPrinting the Date

In the HEADING section, the reserved variable $current-date prints the date and the time. This variable is initialized with the date and time of the client machine when the program starts to run. SQR provides predefined, or reserved, variables for a variety of uses.

In this example, the complete command is PRINT $current-date (1,1) EDIT 'DD/Mon/YYYY'. It prints the date and time at position 1,1 of the heading. The EDIT argument specifies an edit mask, or format, for printing the date. SQR provides a variety of edit masks for use in formatting numbers, dates, and strings.

See PRINT.

Note that the PRINT command for the report title precedes the command for the $current-date reserved variable, even though the date is on the left and the title is on the right. SQR always assembles a page in memory before printing, so the order of these commands does not matter if you use the correct print position qualifiers.

The last two commands in the HEADING section print a string of hyphens under the column headings. Note the use of the FILL option with the PRINT command. This tells SQR to fill the specified width with this pattern, which is a useful method to print a line.

The FOOTING section prints the Page n of m as in earlier examples.

See Also

Enterprise PeopleTools 8.50 PeopleBook: SQR for PeopleSoft Developers

Click to jump to top of pageClick to jump to parent topicObtaining Totals

The ex5d.sqr program also prints two totals: a subtotal of customers in each state and a grand total of all customers. These calculations are performed with two numeric variables, one for the subtotals and one for the grand totals. These variables are:

SQR for PeopleSoft has a small set of variable types. The most common types are numeric variables and string variables. All numeric variables in SQR are preceded by a pound sign (#) and all string variables are preceded by a dollar sign ($). An additional SQR variable type is the date variable.

In SQR for PeopleSoft, numeric and string variables are not explicitly declared. Instead, they are implicitly defined by their first use. All numeric variables start out as zero and all string variables start out as null, so they do not need to be initialized. The string variables are of varying length and can hold long strings of characters and short ones. Assigning a new value to a string variable automatically adjusts its length.

In the list_customers procedure, #state_total and #cust_total are set to zero at the beginning of the procedure. This initialization is optional and is done for clarity only. The #state_total variable is incremented by 1 for every row that is selected.

When the value of state changes, the program calls the state_tot procedure and prints the value of #state_total. Note the use of the EDIT 999,999 edit mask, which formats the number.

This procedure also employs the LET command. LET is the assignment command in SQR, for building complex expressions. Here, LET adds the value of #state_total to #cust_total. At the end of the procedure, #state_total is reset to zero.

The list_customers procedure contains an example of the SQR if-then-else logic. The condition starts with IF followed by an expression. If the expression evaluates to true or to a number other than zero, the subsequent commands are run. Otherwise, if there is an ELSE part to the IF, those commands are run. IF commands always end with an END-IF.

In ex5d.sqr, the value of #cust_total is examined. If it is greater than zero, the query has returned rows of data, and the program prints the string Total Customers: and the value of #cust_total.

If #cust_total is zero, the query has not returned any data. In that case, the program prints the string No customers.

Click to jump to top of pageClick to jump to parent topicUsing Hyphens and Underscores

Many SQR commands, such as BEGIN-PROGRAM and BEGIN-SELECT, use a hyphen, whereas procedure and variable names use an underscore.

Procedure and variable names can contain either a hyphen or underscore, but it's best to use underscores in procedure and variable names to distinguish them from SQR commands. It also prevents confusion when you mix variable names and numbers in an expression, where hyphens could be mistaken for minus signs.

Click to jump to parent topicSetting Break Procedures with BEFORE and AFTER

When you print variables with ON-BREAK, you can automatically call procedures before and after each break in a column. The BEFORE and AFTER qualifiers provide this capability. For example:

begin-select state (,1) on-break before=state_heading after=state_tot

The BEFORE qualifier automatically calls the state_heading procedure to print headings before each group of records of the same state. Similarly, the AFTER qualifier automatically calls the state_tot procedure to print totals after each group of records.

All BEFORE procedures are automatically invoked before each break, including the first: that is, before the select paragraph is even processed. Similarly, all AFTER procedures are invoked after each break, including the last group: that is, upon completion of the select paragraph.

Click to jump to top of pageClick to jump to parent topicUnderstanding the Order of Events

You can define a hierarchy of break columns by using the LEVEL qualifier of ON-BREAK. In the ex5c.sqr sample program, for example, state was defined as LEVEL=1 and city as LEVEL=2.

When a break occurs at one level, it also forces breaks on variables with higher LEVEL qualifiers. In the sample program, a break on state also means a break on city.

A break on a variable can initiate many other events. The value can be printed, lines can be skipped, procedures can be called automatically, and the old value can be saved. Knowing the order of events is important, particularly where multiple ON-BREAK columns exist.

The following select paragraph has breaks on three levels:

begin-select state (,1) on-break level=1 after=state_tot skiplines=2 city (,7) on-break level=2 after=city_tot skiplines=1 zip (,45) on-break level=3 after=zip_tot from customers order by state, city, zip end-select

The breaks are processed in the following way:

  1. When zip breaks, the city_tot procedure is run.

  2. When city breaks, first the zip_tot procedure is run, then the city_tot procedure is run, and one line is skipped (SKIPLINES=1).

    Both city and zip are printed in the next record.

  3. When state breaks, the zip_tot, city_tot, and state_tot procedures are processed in that order.

    One line is skipped after the city_tot procedure is run, and two lines are skipped after the state_tot procedure is run. All three columns—state, city, and zip—are printed in the next record.

The following program (ex5e.sqr) demonstrates the order of events in break processing. It has three ON-BREAK columns, each with a LEVEL argument and a BEFORE and AFTER procedure. The BEFORE and AFTER procedures print strings to indicate the order of processing.

Program ex5e.sqr begin-setup declare-Layout default end-declare end-setup begin-program do main end-program begin-procedure a print 'AFTER Procedure for state LEVEL 1' (+1,40) end-procedure begin-procedure b print 'AFTER Procedure city LEVEL 2' (+1,40) end-procedure begin-procedure c print 'AFTER Procedure zip LEVEL 3' (+1,40) end-procedure begin-procedure aa print 'BEFORE Procedure state LEVEL 1' (+1,40) end-procedure begin-procedure bb print 'BEFORE Procedure city LEVEL 2' (+1,40) end-procedure begin-procedure cc print 'BEFORE Procedure zip LEVEL 3' (+1,40) end-procedure begin-procedure main local begin-select add 1 to #count print 'Retrieved row #' (+1,40) print #count (,+10)Edit 9999 position (+1) state (3,1) On-Break Level=1 after=a before=aa city (3,10) On-Break Level=2 after=b before=bb zip (3,25) On-Break Level=3 after=c before=cc Edit xxxxx next-listing Need=10 from customers order by state,city,zip end-select end-procedure begin-heading 3 print $current-date (1,1) edit 'DD-MM-YYYY' page-number (1,60) 'Page ' last-page () ' of ' print 'STATE' (3,1) print 'CITY' (3,10) print 'ZIP' (3,25) print 'Break Processing sequence' (3,40) end-heading

The output for the ex5e.sqr program is:

02-05-2004 Page 1 of 3 STATE CITY ZIP Break Processing sequence BEFORE Procedure state LEVEL 1 IN Davenport 62130 BEFORE Procedure city LEVEL 2 BEFORE Procedure zip LEVEL 3 Retrieved row #1 Retrieved row #2 Miningville 40622 AFTER Procedure zip LEVEL 3 AFTER Procedure city LEVEL 2 BEFORE Procedure city LEVEL 2 BEFORE Procedure zip LEVEL 3 Retrieved row #3 MI Bell Harbor 40674 AFTER Procedure zip LEVEL 3 AFTER Procedure city LEVEL 2 AFTER Procedure for state LEVEL 1 BEFORE Procedure state LEVEL 1 BEFORE Procedure city LEVEL 2 BEFORE Procedure zip LEVEL 3 Retrieved row #4 NH Frogline 04821 AFTER Procedure zip LEVEL 3 AFTER Procedure city LEVEL 2 AFTER Procedure for state LEVEL 1 BEFORE Procedure state LEVEL 1 BEFORE Procedure city LEVEL 2 BEFORE Procedure zip LEVEL 3 Retrieved row #5 NJ Teaneck 00355 AFTER Procedure zip LEVEL 3 AFTER Procedure city LEVEL 2 AFTER Procedure for state LEVEL 1 BEFORE Procedure state LEVEL 1 BEFORE Procedure city LEVEL 2 BEFORE Procedure zip LEVEL 3 Retrieved row #6 NM Big Falls 87893 AFTER Procedure zip LEVEL 3 AFTER Procedure city LEVEL 2 AFTER Procedure for state LEVEL 1 BEFORE Procedure state LEVEL 1 BEFORE Procedure city LEVEL 2 BEFORE Procedure zip LEVEL 3 02-05-2004 Page 2 of 3 STATE CITY ZIP Break Processing sequence Retrieved row #7 NY Mamaroneck 10833 AFTER Procedure zip LEVEL 3 AFTER Procedure city LEVEL 2 AFTER Procedure for state LEVEL 1 BEFORE Procedure state LEVEL 1 BEFORE Procedure city LEVEL 2 BEFORE Procedure zip LEVEL 3 ...

The following steps explain the order of processing in detail:

  1. Process BEFORE procedures.

    BEFORE procedures are processed in ascending order by LEVEL before the first row of the query is retrieved. If no data is selected, BEFORE procedures are not run.

  2. Select the first row of data.

  3. Select subsequent rows of data.

    Processing of the select paragraph continues. When a break occurs on any column, it also initiates breaks on columns at the same or higher levels. Events occur in the following order:

    1. AFTER procedures are processed in descending order from the highest level to the level of the current ON-BREAK column.

    2. SAVE variables are set with the value of the previous ON-BREAK column.

    3. BEFORE procedures are processed in ascending order from the current level to the highest level.

    4. If SKIPLINES was specified, the current line position is advanced.

    5. The value of the new group is printed (unless PRINT=NEVER is specified).

  4. Process AFTER procedures.

    After the select paragraph is complete, if any rows were selected, AFTER procedures are processed in descending order by LEVEL.

See Saving a Value When a Break Occurs.

Click to jump to parent topicControlling Page Breaks with Multiple ON-BREAK Columns

Where multiple columns have ON-BREAK, page breaks need careful planning. While having a page break within a group, you probably would not want to have one within a record.

You can prevent page breaks within a record by following four simple rules:

Click to jump to parent topicSaving a Value When a Break Occurs

In ex5d.sqr, the state_tot procedure prints the total number of customers per state. Because it is called with the AFTER argument, this procedure is run only after the value of the ON-BREAK column, state, has changed.

Sometimes, however, you may want to print the previous value of the ON-BREAK column in the AFTER procedure. For example, you may want to print the state name and the totals for each state. Printing the value of state will not work because its value will have changed by the time the AFTER procedure is called.

The solution is to save the previous break value in a string variable. To do this, use the SAVE qualifier of ON-BREAK. For example:

begin-select state (,1) on-break after=state_tot save=$old_state

You can then print the value of $old_state in the state_tot procedure.

Click to jump to parent topicUsing ON-BREAK on a Hidden Column

In some reports, you may want to use the features of break processing without printing the ON-BREAK option. For example, you may want to incorporate the ON-BREAK option into a subheading. This format might make your report more readable. It is also useful when you want to leave room on the page for additional columns.

To create such a report, you can hide the break option using the PRINT=NEVER qualifier and print it in a heading procedure that is called by BEFORE.

The following code is based on the ex5b.sqr program, with the key lines shown like this:

Program ex5f.sqr begin-program do list_customers end-program begin-procedure list_customers begin-select ​state () on-break before=state_heading print=never level=1 city (,1) on-break level=2 ​name (,18) phone (,49) position (+1) ! Advance to the next line from customers order by state, city, name end-select end-procedure ! list_customers begin-procedure state_heading print 'State: ' (+1,1) bold ! Advance a line and print 'State:' print &state (,8) bold ! Print the state column here print 'City' (+1,1) bold ! Advance a line and print 'City' print 'Name' (,18) bold print 'Phone' (,49) bold print '-' (+1,1,58) fill position (+1) ! Advance to the next line end-procedure ! state_heading

Note. This program has no HEADING section. Instead, a procedure prints column headings for each state rather than at the top of each page. The &state variable can be referenced throughout the program, even though the state column was not printed as part of the break.

Examine the following line in the program from the select paragraph:

state () on-break before=state_heading print=never level=1

This line defines the break processing for state. The BEFORE qualifier specifies that the state_heading procedure is automatically called when the state changes. In this program, the break is set to LEVEL=1.

The PRINT=NEVER qualifier hides the state column and specifies that it is not printed as part of the select paragraph. Instead, it is printed in the state_heading procedure. In this procedure, the state column is referred to as the &state column variable.

The city column is assigned a LEVEL=2 break.

The output for the ex5f.sqr program is:

State: IN City Name Phone ---------------------------------------------------------- Davenport Harold Alexander Fink 3015553645 Miningville Harry's Landmark Diner 3175550948 State: MI City Name Phone ---------------------------------------------------------- Bell Harbor Sam Johnson 3135556732 State: NH City Name Phone ---------------------------------------------------------- Frogline Jerry's Junkyard Specialties 6125552877 State: NJ City Name Phone ---------------------------------------------------------- Teaneck Clair Butterfield 2015559901 State: NM City Name Phone ---------------------------------------------------------- Big Falls Joe Smith and Company 8085552124 State: NY City Name Phone ---------------------------------------------------------- Mamaroneck Harriet Bailey 9145550144 New York John Conway 2125552311 Corks and Bottles, Inc. 2125550021 Kate's Out of Date Dress Shop 2125559000 Queens Eliot Richards 2125554285 State: OH City Name Phone ---------------------------------------------------------- Cleveland Quentin Fields 2165553341 Everretsville Gregory Stonehaven 2165553109 Zanesville Isaiah J Schwartz and Company 5185559813

Click to jump to parent topicPerforming Break Processing on Numeric Values

You cannot use ON-BREAK with SQR numeric variables. To perform break processing on a numeric variable, you must first move its value to a string variable and then set ON-BREAK on that. For example:

begin-select amount_received &amount move &amount to $amount $$9,999.99 print $amount (+1,1) on-break from cash_receipts order by amount_received end-select

The maximum number of ON-BREAK levels is determined by the ON-BREAK setting in the [Processing-Limits] section of the PSSQR.INI file. The default is 30, but you can increase this setting. Its maximum value is 64K-1 (65,535).

See Also

Enterprise PeopleTools 8.50 PeopleBook: SQR Language Reference for PeopleSoft