Michael Coughlan

Home > Other > Michael Coughlan > Page 35

The report format is given in the template shown in Figure 12-1.

  Figure 12-1. Report template for Aromamora Summary Sales Report

  Notes

  Here are some things to consider:

  • The B in the OilId indicates that this is a base oil.

  • UnitSize represents the size of the oil container purchased. There are only three sizes for base

  oils: 1 (50ml), 2 (100ml), and 3 (200ml).

  • ValueOfSales is the sum of the ValueOfSale calculated for each record.

  274

  Chapter 12 ■ advanCed data deClaration

  • ValueOfSale is UnitsSold * UnitCost(OilNum,Unitsize).

  • The OilName and UnitCost are obtained from a prefilled table of values (see the program

  outline for details). The two-dimensional table required to hold these values is shown in

  Figure 12-2.

  Figure 12-2. Table of oil names and unit costs

  Oil Costs Table

  Aromamora sells 14 kinds of base oil. The cost of each type of base oil in each of the three container sizes (50ml, 100ml, and 200ml) is given by the table in Figure 12-2. For instance, almond oil costs $02.00 for the 50ml size, $03.50 for 100ml size, and $06.50 for 200ml size.

  Example 12-1 demonstrates how you can translate the information given in Figure 12-1 into a prefilled COBOL

  table. You start by laying down in memory the information you want in the table. Obviously you have to omit the dollar sign and decimal point because those are text and you need to do calculations on the data in the table. At this point, you have a block of undifferentiated data in memory as follows:

  Almond 020003500650

  Aloe vera 047508501625

  Apricot kernel 025004250775

  Avocado 027504750875

  Coconut 027504750895

  Evening primrose037506551225

  Grape seed 018503250600

  Peanut 027504250795

  275

  Chapter 12 ■ advanCed data deClaration

  Jojoba 072513252500

  Macadamia 032505751095

  Rosehip 052509951850

  Sesame 029504250750

  Walnut 027504550825

  Wheatgerm 045007751425

  The final step in creating the table is to use the REDEFINES clause to impose a table definition on the area of memory, as shown in Example 12-1. Once the data is redefined, you can access it using the table. For instance, OilName(9) = Jojoba, and UnitCost(9,2) = 1325.

  Example 12-1. Table Definition of the Two-Dimensional Table Shown in Figure 12-1

  01 OilsTable.

  02 OilTableValues.

  03 FILLER PIC X(28) VALUE "Almond 020003500650".

  03 FILLER PIC X(28) VALUE "Aloe vera 047508501625".

  03 FILLER PIC X(28) VALUE "Apricot kernel 025004250775".

  03 FILLER PIC X(28) VALUE "Avocado 027504750875".

  03 FILLER PIC X(28) VALUE "Coconut 027504750895".

  03 FILLER PIC X(28) VALUE "Evening primrose037506551225".

  03 FILLER PIC X(28) VALUE "Grape seed 018503250600".

  03 FILLER PIC X(28) VALUE "Peanut 027504250795".

  03 FILLER PIC X(28) VALUE "Jojoba 072513252500".

  03 FILLER PIC X(28) VALUE "Macadamia 032505751095".

  03 FILLER PIC X(28) VALUE "Rosehip 052509951850".

  03 FILLER PIC X(28) VALUE "Sesame 029504250750".

  03 FILLER PIC X(28) VALUE "Walnut 027504550825".

  03 FILLER PIC X(28) VALUE "Wheatgerm 045007751425".

  02 FILLER REDEFINES OilTableValues.

  03 BaseOil OCCURS 14 TIMES.

  04 OilName PIC X(16).

  04 UnitCost PIC 99V99 OCCURS 3 TIMES.

  Program

  This is a typical one-level control-break program. I have kept the program simple (see Listing 12-1) to allow you to focus on the declaration and use of the two-dimensional table. Note that in a real situation, the oil-cost table would not be static as it is in this program. The cost data is likely to change, so for maintenance reasons the table would probably be instantiated from a file. A portion of the sales file used to the test the program and the summary report produced from that file are shown in Figure 12-3 in the next section.

  Listing 12-1. Aromamora Base Oils Summary Sales Report

  IDENTIFICATION DIVISION.

  PROGRAM-ID. Listing12-1.

  AUTHOR. Michael Coughlan.

  * This program produces a summary report showing the sales of base oils

  * to Aromamora customers by processing the OilSalesFile. The OilSalesFile is a

  * sequential file ordered on ascending CustomerId. The report is required to be

  * printed in ascending CustomerId order.

  276

  Chapter 12 ■ advanCed data deClaration

  ENVIRONMENT DIVISION.

  INPUT-OUTPUT SECTION.

  FILE-CONTROL.

  SELECT BaseOilsSalesFile ASSIGN TO "Listing12-1.Dat"

  ORGANIZATION IS LINE SEQUENTIAL.

  SELECT SummaryReport ASSIGN TO "Listing12-1.Rpt"

  ORGANIZATION IS LINE SEQUENTIAL.

  DATA DIVISION.

  FILE SECTION.

  FD BaseOilsSalesFile.

  01 SalesRec.

  88 EndOfSalesFile VALUE HIGH-VALUES.

  02 CustomerId PIC X(5).

  02 CustomerName PIC X(20).

  02 OilId.

  03 FILLER PIC X.

  03 OilNum PIC 99.

  02 UnitSize PIC 9.

  02 UnitsSold PIC 999.

  FD SummaryReport.

  01 PrintLine PIC X(45).

  WORKING-STORAGE SECTION.

  01 OilsTable.

  02 OilTableValues.

  03 FILLER PIC X(28) VALUE "Almond 020003500650".

  03 FILLER PIC X(28) VALUE "Aloe vera 047508501625".

  03 FILLER PIC X(28) VALUE "Apricot kernel 025004250775".

  03 FILLER PIC X(28) VALUE "Avocado 027504750875".

  03 FILLER PIC X(28) VALUE "Coconut 027504750895".

  03 FILLER PIC X(28) VALUE "Evening primrose037506551225".

  03 FILLER PIC X(28) VALUE "Grape seed 018503250600".

  03 FILLER PIC X(28) VALUE "Peanut 027504250795".

  03 FILLER PIC X(28) VALUE "Jojoba 072513252500".

  03 FILLER PIC X(28) VALUE "Macadamia 032505751095".

  03 FILLER PIC X(28) VALUE "Rosehip 052509951850".

  03 FILLER PIC X(28) VALUE "Sesame 029504250750".

  03 FILLER PIC X(28) VALUE "Walnut 027504550825".

  03 FILLER PIC X(28) VALUE "Wheatgerm 045007751425".

  02 FILLER REDEFINES OilTableValues.

  03 BaseOil OCCURS 14 TIMES.

  04 OilName PIC X(16).

  04 UnitCost PIC 99V99 OCCURS 3 TIMES.

  01 ReportHeadingLine PIC X(41)

  VALUE " Aromamora Base Oils Summary Sales Report".

  277

  Chapter 12 ■ advanCed data deClaration

  01 TopicHeadingLine.

  02 FILLER PIC X(9) VALUE "Cust Id".

  02 FILLER PIC X(15) VALUE "Customer Name".

  02 FILLER PIC X(7) VALUE SPACES.

  02 FILLER PIC X(12) VALUE "ValueOfSales".

  01 ReportFooterLine PIC X(43)

  VALUE "************** End of Report **************".

  01 CustSalesLine.

  02 PrnCustId PIC B9(5).

  02 PrnCustName PIC BBBX(20).

  02 PrnCustTotalSales PIC BBB$$$$,$$9.99.

  01 CustTotalSales PIC 9(6)V99.

  01 PrevCustId PIC X(5).

  01 ValueOfSale PIC 9(5)V99.

  PROCEDURE DIVISION.

  Print-Summary-Report.

  OPEN OUTPUT SummaryReport

  OPEN INPUT BaseOilsSalesFile

  WRITE PrintLine FROM ReportHeadingLine AFTER ADVANCING 1 LINE

  WRITE PrintLine FROM TopicHeadingLine AFTER ADVANCING 2 LINES

  READ BaseOilsSalesFile

  AT END SET EndOfSalesFile TO TRUE

  END-Read

  PERFORM PrintCustomer
Lines UNTIL EndOfSalesFile

  WRITE PrintLine FROM ReportFooterLine AFTER ADVANCING 3 LINES

  CLOSE SummaryReport, BaseOilsSalesFile

  STOP RUN.

  PrintCustomerLines.

  MOVE ZEROS TO CustTotalSales

  MOVE CustomerId TO PrnCustId, PrevCustId

  MOVE CustomerName TO PrnCustName

  PERFORM UNTIL CustomerId NOT = PrevCustId

  COMPUTE ValueOfSale = UnitsSold * UnitCost(OilNum, UnitSize)

  ADD ValueOfSale TO CustTotalSales

  READ BaseOilsSalesFile

  AT END SET EndOfSalesFile TO TRUE

  END-Read

  END-PERFORM

  MOVE CustTotalSales TO PrnCustTotalSales

  WRITE PrintLine FROM CustSalesLine AFTER ADVANCING 2 LINES.

  278

  Chapter 12 ■ advanCed data deClaration

  Test Data and Results

  Due to space constraints, only a portion of the test data file is shown (see Figure 12-3).

  Figure 12-3. Partial test data and results produced

  279

  Chapter 12 ■ advanCed data deClaration

  The REDEFINES Clause

  So far, I have dealt informally with the REDEFINES clause. You have seen how to use it to create a prefilled table of values, but I have not formally defined what REDEFINES does or explored its other uses.

  When a file contains different types of records, you must create a separate record description for each record type in the file’s FD entry. You have seen that all these record descriptions map on to the same area of storage. They are, in effect, redefinitions of the area of storage. What the REDEFINES clause allows you to do is to achieve the same effect for units smaller than a record and in parts of the DATA DIVISION other than the FILE SECTION. The REDEFINES clause lets you give different data descriptions to the same area of storage.

  REDEFINES Syntax

  The syntax metalanguage for the REDEFINES clause is given in Figure 12-4. Identifier1 is the data item that originally defines the area of storage, and Identifier2 is the data item that redefines it.

  Figure 12-4. Syntax metalanguage for the REDEFINES clause

  REDEFINES Notes

  The metalanguage defines the syntax of the REDEFINES clause, but there are also a number of semantic rules that must be obeyed when you use REDEFINES:

  • The REDEFINES clause must immediately follow Identifier2 (that is, REDEFINES must come

  before PIC [see Example 12-2]).

  • The level numbers of Identifier1 and Identifier2 must be the same and cannot be 66 or 88.

  • The data description of Identifier1 cannot contain an OCCURS clause (that is, you can’t

  redefine a table element).

  • If there are multiple redefinitions of the same area of storage, then they must all redefine the

  data item that originally defined the area (see Example 12-5).

  • The redefining entries (Identifier2) cannot contain VALUE clauses except in condition

  name entries.

  • No entry with a level number lower (that is, higher in the hierarchy) than the level number of

  Identifier1 and Identifier2 can occur between Identifier1 and Identifier2.

  • Entries redefining the area must immediately follow those that originally defined it.

  • Only entries subordinate to Identifier1 are allowed between Identifier1 and Identifier2.

  • The REDEFINES clause must not be used for records (01 level) described in the FILE SECTION

  because multiple 01 entries for the same file are implicit redefinitions of the first 01 level

  record.

  280

  Chapter 12 ■ advanCed data deClaration

  REDEFINES Examples

  The best way to understand how the REDEFINES clause works is to explore some of the ways it may be used through a number of examples.

  REDEFINES Example 1

  Some COBOL statements, such as UNSTRING, require their receiving fields to be alphanumeric (PIC X) data items. This is inconvenient if the value of the data item is actually numeric, because then a MOVE is required to place the value into a numeric item. If the value contains a decimal point, this creates even more difficulties.

  For example, suppose an UNSTRING statement has just extracted the text value “5432195” from a string, and you want to move this value to a numeric item described as PIC 9(5)V99. An ordinary MOVE is not going to work because the computer will not know that you want the item treated as if it were the value 654321.95.

  The REDEFINES clause allows you to solve this problem neatly because you can UNSTRING the number into

  TextValue and then treat TextValue as if it were described as PIC 9(5)V99 (see Example 12-2). If TextValue contains the alphanumeric value “65432195”, then NumericValue, which REDEFINES it, sees the value as 654321.95 (see Figure 12-5).

  Example 12-2. Redefining an Alphanumeric Item as a Decimal Data Item

  01 RedefinesExample1.

  02 TextValue PIC X(8).

  02 NumericValue REDEFINES TextValue PIC 9(6)V99.

  Figure 12-5. Memory model showing the result of redefinition

  REDEFINES Example 2

  The first example showed how you can use the REDEFINES clause to treat a set of alphanumeric digits as a decimal number. This example explores a similar problem. When a program ACCEPTs a decimal number from a user, the

  decimal point is included. This is a problem because this decimal point is a text character. If you move a numeric literal (such as 1234.55) that contains a decimal point into a numeric data item that contains an assumed decimal point (such as PIC 9(5)V99), the actual and assumed decimal points align. This does not happen when you move an item containing the decimal point text character. In fact, if you move an item containing an actual decimal point into a numeric data item and then try to perform an arithmetic calculation on that data item, the program will crash (halt unexpectedly).

  281

  Chapter 12 ■ advanCed data deClaration

  A solution to this problem is given in Example 12-3. When a number containing an actual decimal point is

  accepted from the user, the UNSTRING verb is used to split the input string into the digits before the decimal point and those after the decimal point. Although WorkArea contains only numeric digits, because it is a group item, its type is alphanumeric, and so it can’t be used in a calculation. The solution is to redefine WorkArea as WorkNum, which is a numeric data item that can be used in calculations. A model of the redefined data items is given in Figure 12-6.

  Example 12-3. Redefining Two Data Items as a Single Numeric Item

  WORKING-STORAGE SECTION.

  01 InputString PIC X(8).

  01 WorkArea.

  02 Fnum PIC 9(5) VALUE ZEROS.

  02 Snum PIC 99 VALUE ZEROS.

  01 WorkNum REDEFINES WorkArea PIC 99999V99.

  01 EditedNum PIC ZZ,ZZ9.99.

  PROCEDURE DIVISION.

  Begin.

  DISPLAY "Enter a decimal number - " WITH NO ADVANCING

  ACCEPT InputString

  UNSTRING InputString DELIMITED BY ".", ALL SPACES

  INTO Fnum, Snum

  MOVE WorkNum TO EditedNum

  DISPLAY "Decimal Number = " EditedNum

  ADD 10 TO WorkNum

  MOVE WorkNum TO EditedNum

  DISPLAY "Decimal Number = " EditedNum

  Figure 12-6. Model showing WorkArea, Fnum, and Snum redefined as WorkNum

  REDEFINES Example 3

  Working with percentages often presents a problem. If the percentage is held as an integer, then calculations are complicated by having to divide by 100. For instance, COMPUTE PercentOfBase = BaseAmount * PercentToApply /100.

  On the other hand, if the percentage is held as a decimal fraction, then calculations are made simpler but communication with users is complicated because now they have to input or print the percentage as a decimal fraction rather than a whole number.

  282<
br />
  Chapter 12 ■ advanCed data deClaration

  The solution is to take in the percentage as an integer value and then use REDEFINES to treat it as a decimal fraction. Example 12-4 is a program fragment that shows how this works.

  Example 12-4. Using REDEFINES to Allow Different Views of a Percentage Value

  DATA DIVISION.

  WORKING-STORAGE SECTION.

  01 PercentToApply PIC 9(3).

  01 Percentage REDEFINES PercentToApply PIC 9V99.

  01 BaseAmount PIC 9(5) VALUE 10555.

  01 PercentOfBase PIC ZZ,ZZ9.99.

  01 PrnPercent PIC ZZ9.

  PROCEDURE DIVISION.

  Begin.

  MOVE 23 TO PercentToApply

  COMPUTE PercentOfBase = BaseAmount * Percentage

  DISPLAY "23% of 10555 is = " PercentOfBase

  MOVE PercentToApply to PrnPercent

  DISPLAY "Percentage applied was " PrnPercent "%"

  STOP RUN.

  REDEFINES Example 4

  The REDEFINES clause is also useful when you need to treat a numeric item as if it had its decimal point in a different place. For instance, Example 12-5 shows how you can use the REDEFINES clause to provide time conversions between seconds, milliseconds, microseconds, and nanoseconds.

  The main purpose of Example 12-5 is to illustrate the rule that if there are multiple redefinitions of an area of storage, they must all refer to the data item that originally defined the area of storage.

  Example 12-5. Time Conversion by Multiple Redefinition

  WORKING-STORAGE SECTION.

  01 NanoSecs PIC 9(10).

  01 MicroSecs REDEFINES NanoSecs PIC 9999999V999.

  01 MilliSecs REDEFINES NanoSecs PIC 9999V999999.

  01 Seconds REDEFINES NanoSecs PIC 9V999999999.

  01 EditedNum PIC Z,ZZZ,ZZZ,ZZ9.99.

  PROCEDURE DIVISION.

  Begin.

  MOVE 1234567895 TO NanoSecs

  MOVE NanoSecs TO EditedNum

  DISPLAY EditedNum " NanoSecs"

  283

 

‹ Prev