Advanced Internal Tables, Part 1
- Chapter Objectives
- Testing and Modifying Internal Table Contents
- Obtaining Information about an Internal Table
- Copying Data from one Internal Table to Another
- Using the editor-call Statement
- Inserting Rows into an Internal Table
- Modifying Rows in an Internal Table
- Deleting Internal Table Contents
- Creating Top 10 Lists Using append sorted by
- Filling an Internal Table Using collect
- Summary
- Q&A
- Workshop
Chapter Objectives
After you complete this chapter, you should be able to:
- Recognize the table body operator and use it to test for the existence of data in an internal table, and to compare the contents of two internal tables for equality
- Determine the number of rows in an internal table using describe and sy-tfill
- Copy the contents from one internal table to another using the table body operator and the append lines and insert lines statements
- View and modify internal tables using editor-call
- Use the insert and modify statements to change the internal table contents
- Delete rows from an internal table using delete, delete ... where, clear, clear it[], refresh, and free
- Fill an internal table using append sorted by and collect
Testing and Modifying Internal Table Contents
Use the following constructs to test and modify the contents of internal tables:
- The table body operator
- describe table
- append lines
- insert lines
- editor-call
- insert
- modify
- free
- delete
- clear
- refresh
- append sorted by
- collect
The body of an internal table is represented by the syntax it[], where it is the name of any internal table. it[] means “the body of the internal table it.” There cannot be anything between the square brackets; they must be written precisely as shown. You can use this syntax to perform efficient table operations that do not require the use of a header line. These operations are described throughout this chapter.
If an internal table does not have a header line, the internal table name itself represents the body. For example, if internal table it does not have a header line, you can use either it[] or it to represent the body; they are equivalent.
Obtaining Information about an Internal Table
You can obtain the following commonly needed information about an internal table:
- Whether the internal table contains data
- How many rows it contains
Determining Whether an Internal Table Is Empty
If the body of an internal table contains only initial values (blanks and spaces), it is empty. Therefore, to determine whether an internal table contains any rows, test the body with the following statement:
1 if it[] is initial.
If the test is true, the internal table is empty. When false, it contains at least one row.
Determining the Number of Rows in an Internal Table
To determine the number of rows in an internal table, use the sy-tfill variable. It is set by the describe table statement.
Syntax for the describe table Statement
The following is the syntax for the describe table statement.
1 describe table <i>it</i> [lines <i>i</i>] [occurs <i>j</i>].
where:
- it is the name of an internal table.
- i and j are numeric variables.
This statement fills the three system variables shown in Table 12.1.
sy-tfill | Number of rows |
sy-tleng | Length of a row in bytes |
sy-toccu | Current value of the occurs clause |
The following points apply:
- If the lines i addition is specified, the number of rows is placed in both sy-tfill and i.
- If the occurs j addition is specified, the size of the occurs clause is placed in both sy-toccu and j.
NOTE |
|
Sample Program that Obtains Information About an Internal Table
Listing 12.1 shows a sample program that obtains information about an internal table.
Listing 12.1 The describe table Statement Uses System Variables to Quantify Table Contents
1 1 report ztx1201.<br/> 2 data: begin of it occurs 3,<br/> 3 f1 value 'X',<br/> 4 end of it,<br/> 5 n type i.<br/> 6 <br/> 7 if it[] is initial.<br/> 8 write: / 'it is empty'.<br/> 9 endif.<br/>10<br/>11 append: it, it, it. "same as writing 'append it' 3 times.<br/>12<br/>13 if not it[] is initial.<br/>14 write: / 'it is not empty'.<br/>15 endif.<br/>16<br/>17 write: / 'number of rows from sy-tabix:', sy-tabix.<br/>18 describe table it lines n.<br/>19 write: / 'number of rows from sy-tfill:', sy-tfill,<br/>20 / 'length of a row from sy-tleng:', sy-tleng,<br/>21 / 'occurs value from sy-toccu:', sy-toccu.
The code in Listing 12.1 produces this output:
1 it is empty <br/>it is not empty <br/>number of rows from sy-tabix: 3<br/>number of rows from sy-tfill: 3<br/>length of a row from sy-tleng: 1 <br/>occurs value from sy-toccu: 3
- Line 7 compares the body of the internal table using the table body operator with initial values. The internal table does not yet contain any rows, so the test is true.
- Line 11 uses the chain operator (:) to append three identical rows to it.
- Line 13 tests the body again. This time, the test is preceded by a logical not. The internal table contains data, so this test is true.
- After each append statement, the value of sy-tabix is set to the number of rows in the internal table. Line 17 writes out its value.
- Line 18 uses the describe statement to obtain the number of rows and places it in sy-tfill. It also obtains the row length and size of the occurs clause and places them into sy-tleng and sy-toccu.
TIP |
|
Copying Data from one Internal Table to Another
If two internal tables have the same structure, use the following statement to duplicate the contents of one internal table in another:
1 it2[] = it1[].
The preceding statement copies the contents of the body of it1 and places it in the body of it2. Any existing contents in it2 are overwritten. The contents of the header lines, if either internal table has one, remain unchanged. This is the most efficient way to copy the contents from one internal table to another.
NOTE |
|
Copying a Portion of an Internal Table
If you want to copy a portion of an internal table to another, or if you want to leave the contents of the target table in place, use the append lines and insert lines statements.
Using the append lines Statement
Use the append lines statement when you want to append rows to the end of the target table.
Syntax for the append lines Statement
The following is the syntax for the append lines statement.
1 append lines of <i>it1</i> [from <i>nf</i>] [to <i>nt</i>] to <i>it2</i>.
where:
- it1 and it2 are internal tables with or without header lines.
- nf and nt are numeric variables, literals, or constants.
The following points apply:
- The structures of it1 and it2 must match.
- nf is the index of the first row to be copied from it1. If the from addition is not specified, copying begins from the first row of it1.
- nt is the index of the last row to be copied from it1. If the to addition is not specified, copying continues to the last row of it1.
- If neither from nor to are specified, the entire table is appended.
- After the append lines statement has executed, sy-tabix contains the number of rows in the table.
TIP Using append lines is three to four times faster than using append to add the rows one at a time.
Using the insert lines Statement
Use the insert lines statement when you want to insert rows at a place other than the end into the target table.
Syntax for the insert lines Statement
The following is the syntax for the insert lines statement.
1 insert lines of <i>it1</i> [from <i>nf</i>] [to <i>nt</i>] into <i>it2</i> [index <i>nb</i>].
where:
- it1 and it2 are internal tables with or without header lines.
- nf, nt, and nb are numeric variables, literals, or constants.
All of the points that apply to the append lines statement also apply here. The difference is that rows from it1 are inserted into it2 before row number nb. If the value of nb is the number of rows in it2 plus 1, the row is appended to the end of it2. If nb is greater than that, the row is not appended and sy-subrc is set to 4. If nb is less than 1, a runtime error occurs.
You can use this statement inside or outside of loop at it2. If used outside, you must specify the index addition. Inside, index is optional. If it is not specified, the current row number in it2 is assumed.
Sample Program that Copies Data Between Internal Tables
Listing 12.2 shows a sample program that copies data from one internal table to another.
Listing 12.2 This Program Copies the Data from One Internal Table to Another Using the append lines and insert lines Statements
1 1 report ztx1202.<br/> 2 data: begin of it1 occurs 10,<br/> 3 f1,<br/> 4 end of it1,<br/> 5 it2 like it1 occurs 10 with header line,<br/> 6 alpha(10) value 'ABCDEFGHIJ'.<br/> 7 <br/> 8 do 10 times varying it1-f1 from alpha+0 next alpha+1.<br/> 9 append it1.<br/>10 enddo.<br/>11<br/>12 append lines of it1 from 2 to 5 to it2.<br/>13 loop at it2.<br/>14 write it2-f1.<br/>15 endloop.<br/>16<br/>17 insert lines of it1 from 8 into it2 index 2.<br/>18 skip.<br/>19 loop at it2.<br/>20 write it2-f1.<br/>21 endloop.<br/>22<br/>23 loop at it2.<br/>24 if it2-f1 >= 'E'.<br/>25 insert lines of it1 to 1 into it2.<br/>26 endif.<br/>27 endloop.<br/>28<br/>29 skip.<br/>30 loop at it2.<br/>31 write it2-f1.<br/>32 endloop.<br/>33<br/>34 skip.<br/>35 it2[] = it1[].<br/>36 loop at it2.<br/>37 write it2-f1.<br/>38 endloop.
The code in Listing 12.2 produces this output:
1 B C D E <br/><br/>B H I J C D E <br/><br/>B A H A I A J C D A E<br/><br/>A B C D E F G H I J
- Lines 8 through 10 fill it1 with 10 rows containing the first 10 letters of the alphabet.
- Line 12 appends rows 2 through 5 of it1 to it2. it2 now has four rows containing the letters B through E.
- On line 17, the to addition is not specified, so the end of it1 is assumed. This inserts rows 8, 9, and 10 from it1 into it2 before row 2.
- On line 24, if the letter in it2-f1 is greater than or equal to E, row 1 of it1 is inserted before the current row of it2. (The from addition is not specified, so the beginning of it1 is assumed.) This results in four rows being inserted. In the output, they are the 'A' values.
- Line 35 copies the contents of it1 to it2, completely overlaying the existing contents.
Comparing the Contents of Two Internal Tables
You can use the table body operator to compare the contents of two internal tables, as shown here:
1 if it1[] = it2[].
To use this construct, the internal tables must have the same structure. If they do not, you will have to compare them manually, row by row.
This statement is true when it1 and it2 contain the same number of rows and the contents of each row are the same.
TIP |
|
Using the editor-call Statement
The editor-call statement displays the contents of an internal table to the user in an editor similar to the ABAP/4 source code editor. It is useful for debugging and as a simple interface for allowing the user to enter and modify data in tabular form.
Syntax for the editor-call Statement
The following is the syntax for the editor-call statement.
1 editor-call for <i>it</i> [title <i>t</i>] [display mode]
where:
- it is the name of an internal table.
- t is a literal, constant, or variable.
The following points apply:
- it can only contain type c components.
- The maximum length for a row is 72 characters.
- t is the text displayed in the title bar of the editor window.
The display mode addition causes the data to be displayed in the editor in display mode. The user will be able to search and scroll, but will not be able to change the contents.
After viewing or modifying the internal table contents via the editor, the user presses one of these buttons: Save, Back, Exit, or Cancel. Save saves the changes made to the internal table contents and returns to the program. Back, Exit, and Cancel leave the editor and return to the program. If changes have been made, the user is prompted to save or cancel the changes.
After the editor-call statement has executed, sy-subrc is set to the values shown in Table 12.2.
A save was performed. The contents of the internal table might or might not be changed. | |
The user did not perform a save. The contents of the internal table are unchanged. |
Listing 12.3 shows a sample program that uses the editor-call statement. In this example, the internal table is filled with five lines and displayed in the editor so that the user can modify the data. The contents are then written out, and a message is also written to indicate whether a change was performed.
Listing 12.3 Use the editor-call Statement to View, Edit, and Debug the Contents of an Internal Table.
1 1 report ztx1203.<br/> 2 data: begin of it occurs 10,<br/> 3 t(72), "text<br/> 4 end of it,<br/> 5 save_it like it occurs 10. "will contain copy of the original<br/> 6 <br/> 7 it-t = 'Name :'. append it.<br/> 8 it-t = 'Address :'. append it.<br/> 9 it-t = 'Phone :'. append it.<br/>10 it-t = 'Freeform Text '. append it.<br/>11 clear it-t with '-'. append it.<br/>12<br/>13 save_it = it[]. "same as: save_it[] = it[].<br/>14 editor-call for it title 'Freeform Entry'.<br/>15 if sy-subrc = 4. "user did not perform a save<br/>16 write: / 'Data was not changed'.<br/>17 elseif save_it[] <> it[]. "user performed a save<br/>18 write: / 'Data was changed'.<br/>19 else.<br/>20 write: / 'Data was not changed'.<br/>21 endif.<br/>22 write: / sy-uline(72).<br/>23 loop at it.<br/>24 write: / it-t.<br/>25 endloop.
If no data is entered when the editor is displayed, the code in Listing 12.3 produces this output:
1 Data was not changed <br/>-----------------------------------------------------------------------<br/>Name : <br/>Address : <br/>Phone : <br/>Freeform Text <br/>-------------------------------------------------------------------
- Lines 2 through 4 define an internal table having a single component t, character length 72.
- Line 5 defines a second internal table like the first. It will be used to hold a reference copy of the data in it. It does not have a header line. The header line has been left off because it is not needed in this program.
- Lines 7 through 11 append five lines to the internal table from the header line.
- Line 13 copies the body of it to the body of save_it. Because save_it does not have a header line, the left side of the assignment can be written with or without square brackets.
- Line 14 displays the contents of the internal table in the editor with the title Freeform Entry.
- Line 15 checks the value of sy-subrc to determine whether the user performed a save. If he did not, it is not possible that data was changed and a message is written out.
- Line 17 compares the new contents of it with the reference copy in save_it. If they are different, a message is written out. If they are the same, line 20 writes out a message to indicate this.
- Lines 22 writes out an underline 72 characters long.
- Lines 23 through 25 write out the new contents of the internal table, including any user modifications.
Inserting Rows into an Internal Table
To insert a single row into an internal table, use the insert statement.
Syntax for the insert Statement
The following is the syntax for the insert statement.
insert [wa into] it [index n]
where:
- wa is a work area with the same structure as a row of internal table it.
- n is a numeric literal, variable, or constant.
The following points apply:
- If wa is specified, the contents of wa are inserted into it. wa must have the same structure as it.
- If wa is not specified, the contents of the header line are inserted into it. If it does not have a header line, wa must be specified.
- If index is specified, the new row is inserted before row n. Row n then becomes row n+1.
- The insert statement can be used inside or outside of loop at it. If it is outside, the index addition must be specified. If it is inside, index is optional. If it is not specified, the current row is assumed.
Listing 12.4 contains a sample program that uses the insert statement.
Listing 12.4 Use the insert Statement to Insert a Single Row into an Internal Table
1 1 report ztx1204.<br/> 2 data: begin of it occurs 5,<br/> 3 f1 like sy-index,<br/> 4 end of it.<br/> 5 <br/> 6 do 5 times.<br/> 7 it-f1 = sy-index.<br/> 8 append it.<br/> 9 enddo.<br/>10<br/>11 it-f1 = -99.<br/>12 insert it index 3.<br/>13<br/>14 loop at it.<br/>15 write / it-f1.<br/>16 endloop.<br/>17<br/>18 loop at it where f1 >= 4.<br/>19 it-f1 = -88.<br/>20 insert it.<br/>21 endloop.<br/>22<br/>23 skip.<br/>24 loop at it.<br/>25 write / it-f1.<br/>26 endloop.
The code in Listing 12.4 produces this output:
1 1 <br/> 2 <br/> 99- <br/> 3 <br/> 4 <br/> 5 <br/><br/> 1 <br/> 2 <br/> 99- <br/> 3 <br/> 88- <br/> 4 <br/> 88- <br/> 5
- Lines 6 through 9 append five rows containing the numbers 1 through 5 to it.
- Line 11 assigns to the header line component it-f1 a value of -99.
- Line 12 inserts the header line of it as new row into the body of it before row 3. The existing row 3 becomes row 4 after the insert.
- Line 18 retrieves those rows from the internal table that have an f1 value greater than or equal to 4. Before each row, line 20 inserts a new row from the header line of it. Prior to the insert, line 19 changed the f1 component to contain -88.
12
TIP |
|
When inserting a new row into it inside of a loop at it, the insert does not affect the internal table immediately, but instead it becomes effective on the next loop pass. When inserting a row after the current row, the table is re-indexed at the endloop, sy-tabix is incremented, and the next loop pass processes the row pointed to by sy-tabix. For example, suppose you are in the third loop pass and you insert a record before row 4. When endloop is executed, the new row becomes row 4, the old row 4 becomes row 5, and so on. Sy-tabix is incremented by 1, and the next loop pass processes the newly inserted record.
If, inside of a loop, you insert a row before the current row, the table is again re-indexed at the endloop. This time, however, sy-tabix is incremented by 1 plus the number of rows inserted before the current row. The next time through the loop, the row following the current row is processed. Suppose, for example, in the third loop pass you insert a row before row 3. At the endloop, the new row becomes row 3, row 3 becomes row 4, and so on. The row you just processed now has an index of 4. sy-tabix is incremented by 2, which gives 5. Row 4 was re-indexed to 5, so it is processed on the next loop pass.
Modifying Rows in an Internal Table
To modify the contents of one or more rows of an internal table, use the modify statement.
Syntax for the modify Statement
The following is the syntax for the modify statement.
1 modify <i>it</i> [from <i>wa</i>] [index <i>n</i>] [transporting <i>c1</i> <i>c2</i> ... [where <i>exp</i>]]
where:
- it is the name of an internal table with or without a header line.
- wa is a work area with the same structure as a row in the body of it.
- n is a numeric literal, variable, or constant.
- c1 and c2 are components of it.
- exp is a logical expression involving components of it.
The following points apply:
- If from wa is specified, the row is overwritten with the contents of wa.
- If from wa is not specified, the row is overwritten with the contents of the header line.
- If index n is specified, n identifies the number of the row that is overwritten.
- modify it can be specified inside or outside of loop at it. If it is outside, index n must be specified. When inside, index n is optional. If it is not specified, the current row is modified.
transporting specifies which components are to be overwritten. Without it, all are overwritten. With it, only the specified components are overwritten. The rest remain unchanged.
Specifying a where condition after transporting causes the specified components to be overwritten in all rows that satisfy the where clause. The left-hand side of each part of exp must specify a component of it. The same component can be specified both after transporting and in exp.
You can’t use modify it with where:
- Inside of loop at it
- With the index addition
Listing 12.5 shows a sample program that modifies the contents of an internal table.
Listing 12.5 Use modify to Overwrite the Existing Contents of One or More Rows of an Internal Table
1 1 report ztx1205.<br/> 2 data: begin of it occurs 5,<br/> 3 f1 like sy-index,<br/> 4 f2,<br/> 5 end of it,<br/> 6 alpha(5) value 'ABCDE'.<br/> 7 <br/> 8 do 5 times varying it-f2 from alpha+0 next alpha+1.<br/> 9 it-f1 = sy-index.<br/>10 append it.<br/>11 enddo.<br/>12<br/>13 it-f2 = 'Z'.<br/>14 modify it index 4.<br/>15<br/>16 loop at it.<br/>17 write: / it-f1, it-f2.<br/>18 endloop.<br/>19<br/>20 loop at it.<br/>21 it-f1 = it-f1 * 2.<br/>22 modify it.<br/>23 endloop.<br/>24<br/>25 skip.<br/>26 loop at it.<br/>27 write: / it-f1, it-f2.<br/>28 endloop.<br/>29<br/>30 it-f2 = 'X'.<br/>31 modify it transporting f2 where f1 <> 10.<br/>32<br/>33 skip.<br/>34 loop at it.<br/>35 write: / it-f1, it-f2.<br/>36 endloop.
The code in Listing 12.5 produces this output:
1 1 A <br/> 2 B <br/> 3 C <br/> 5 Z <br/> 5 E <br/><br/> 2 A <br/> 4 B <br/> 6 C <br/> 10 Z <br/> 10 E <br/><br/> 2 X <br/> 4 X <br/> 6 X <br/> 10 Z <br/> 10 E
- Lines 8 through 11 add five rows to it. Each row contains a sequential number and letter of the alphabet.
- Line 13 modifies the contents of it-f2, giving it a value of 'Z'. it-f1 is not modified, so it still contains the last value added to the table: 5.
- Line 14 overwrites row 4 with the contents of the header line, changing f1 to 5 and f2 to Z.
- Lines 20 through 23 loop through all rows of it, placing each row one at a time into the header line. Line 21 multiplies by 2 the contents of header line component f1. Line 22 copies the contents of the header line back into the current row in the body of it, overwriting it.
- Line 30 modifies the contents of the header line component f2, assigning it a value of ‘X‘.
- Line 31 modifies all rows in the body where f1 is not equal to 10. Only the value of f2 is copied from the header line and overwrites the f2 values in the body. f1 remains unchanged in the body and in the header line.
Deleting Internal Table Contents
To delete contents of an internal table, you can use the following statements:
- free
- refresh
- clear
- delete
Using free to Delete Internal Table Contents
Use the free statement to delete all rows from an internal table and free the associated memory.
Syntax for the free Statement
The following is the syntax for the free statement.
1 free it.
where:
- it is an internal table with or without a header line.
The following points apply:
- All rows are deleted and all memory used by the body of the internal table is freed.
- The header line, if it exists, remains unchanged.
Use free when you are finished using an internal table.
TIP |
|
Listing 12.6 shows how to use the free statement.
Listing 12.6 Use the free Statement to Delete All Rows from an Internal Table and Free the Associated Memory
1 1 report ztx1206.<br/>2 data: begin of it occurs 3,<br/>3 f1 like sy-index,<br/>4 end of it.<br/>5 <br/>6 do 3 times.<br/>7 it-f1 = sy-index.<br/>8 append it.<br/> 9 enddo.<br/>10<br/>11 loop at it.<br/>12 write it-f1.<br/>13 endloop.<br/>14<br/>15 free it.<br/>16 if it[] is initial.<br/>17 write: / 'no rows exist in it after free'.<br/>18 endif.
The code in Listing 12.6 produces this output:
1 1 2 3 <br/>no rows exist in it after free
Line 15 deletes all rows from the internal table and frees the associated memory.
Using refresh to Delete Internal Table Contents
Use the refresh statement to delete all rows from an internal table but leave the memory allocated.
Syntax for the refresh Statement
The following is the syntax for the refresh statement.
1 refresh it.
where:
- it is an internal table with or without a header line.
The following points apply:
- All rows are deleted. All memory used by the body of the internal table remains allocated.
- The header line, if it exists, is unchanged.
Use refresh when you want to delete all rows but you intend to fill the internal table back up again. For example, if you are producing a sales report by department, you might fill the internal table with all sales for one department, process the data, and write it out. Then, after a refresh, you could fill the internal table with the data for the next department, write it out, and so on.
If you intend to refill a table immediately after clearing it, refresh is more efficient than free because it avoids unnecessary memory allocations.
Listing 12.7 shows how to use the refresh statement.
Listing 12.7 Use the refresh Statement to Delete All Rows from an Internal Table
1 1 report ztx1207.<br/> 2 data: begin of it occurs 3,<br/> 3 f1 like sy-index,<br/> 4 end of it,<br/> 5 i like sy-index.<br/> 6<br/> 7 do 3 times.<br/> 8 i = sy-index.<br/> 9 do 3 times.<br/>10 it-f1 = i * sy-index.<br/>11 append it.<br/>12 enddo.<br/>13 write: / ''.<br/>14 loop at it.<br/>15 write it-f1.<br/>16 endloop.<br/>17 refresh it.<br/>18 enddo.<br/>19<br/>20 free it.
The code in Listing 12.7 produces this output:
1 1 2 3<br/> 2 4 6<br/> 3 6 9
- Line 7 begins a loop that is executed three times. It contains a nested inner loop.
- Line 8 stores the current value of sy-index from the outer loop.
- Line 9 begins the inner loop.
- On line 10, the number of the inner loop pass is multiplied by the number of the outer loop pass.
- Line 11 adds each row to the internal table.
- Line 13 begins a new line of output.
- Lines 14 through 16 write out the contents of the internal table.
- Line 17 deletes all rows from the internal table but does not free the memory. Refresh is used here instead of free because the outer loop repeats and refills the internal table again immediately.
- Line 20 deletes all rows and frees the memory for the internal table before the list is shown. This makes the program more efficient.
Using clear with an Internal Table
You can use the clear statement to do either of the following:
- Delete all rows from an internal table and leave the memory allocated.
- Clear the header line (set its components to blanks and zeros).
Syntax for the clear Statement When Used with an Internal Table
The following is the syntax for the clear statement when used with an internal table.
1 clear <i>it</i> | clear <i>it</i>[]
where:
- it is the name of an internal table.
The following points apply:
- If it has a header line, clear it[] deletes all rows. clear it clears the header line.
- If it does not have a header line, both forms delete all rows and leave the memory allocated.
The effect of clear on an internal table is summarized in Table 12.3. The effect of clear varies depending on whether the internal table has a header line or not.
Table 12.3 Effect of CLEAR on an Internal Table
header line |
a header line |
|
clear it | Clears the header line | Deletes all rows |
clear it[] | Deletes all rows | Deletes all rows |
The program in Listing 12.8 illustrates the use of the clear statement with an internal table.
Listing 12.8 The clear Statement Can be Used to Clear the Header Line or Delete the Contents of an Internal Table
1 1 report ztx1208.<br/> 2 data: begin of it occurs 3,<br/> 3 f1,<br/> 4 end of it.<br/> 5 <br/> 6 it-f1 = 'X'.<br/> 7 append: it, it.<br/> 8 <br/> 9 clear it. "it has a header line so clears the header line<br/>10 write: 'f1=', it-f1.<br/>11<br/>12 write: / ''.<br/>13 loop at it.<br/>14 write it-f1.<br/>15 endloop.<br/>16<br/>17 clear it[]. "same as: refresh it.<br/>18 loop at it.<br/>19 write it-f1.<br/>20 endloop.<br/>21 write: / 'sy-subrc=', sy-subrc.
The code in Listing 12.8 produces this output:
1 f1= <br/> X X <br/>sy-subrc= 4
- Line 6 places 'X' in the header line of it.
- Line 7 appends two rows to it; both have 'X' in f1.
- Line 9 clears the header line for it.
- Line 10 writes blanks, showing that the header line for it is clear.
- Lines 13 through 15 produce output to show that the internal table still contains two rows.
- Line 17 clears the body of it, effectively deleting all rows and leaving the memory allocated. The contents of the header line are unchanged.
- Lines 18 through 20 do not produce any output because the internal table is empty.
- Line 21 shows the return code after the loop. This again confirms that no rows exist in the internal table.
Using the delete Statement to Delete Rows from an Internal Table
Using the delete statement, you can delete one or more rows from an internal table.
Syntax for the delete Statement
The following is the syntax for the delete statement.
1 delete <i>it</i> <i>(a)</i> [index <i>n</i>]<br/> <i>(b)</i> [from <i>i</i>] [to <i>j</i>]<br/> <i>(c)</i> [where <i>exp</i>]
where:
- n, fn, and tn are numeric literals, variables, or constants.
- exp is a logical expression involving components of it.
The following points apply:
- The additions following (a), (b), and (c) are all optional.
- Only one of (a), (b), or (c) can be specified.
- delete it without any additions can only be used inside loop at it. In that case, it deletes the current row.
- If index n is specified, the nth row of it is deleted.
- If from i is specified, rows are deleted beginning with the ith row.
- If to j is specified, rows are deleted up to and including the jth row.
- If from is not specified with to, from 1 is assumed.
- If to is not specified with from, to the last row in the table is assumed.
- The expression exp must have a component of it on the left side of each comparison. For example, if it has components f1 and f2, exp could be where f1 = 'A' and f2 = 'B'.
Listing 12.9 shows a sample program that deletes data from an internal table using the delete statement.
Listing 12.9 Deleting Rows from an Internal Table Can also be Done Using the delete Statement
1 1 report ztx1209.<br/>2 data: begin of it occurs 12,<br/>3 f1,<br/>4 end of it,<br/> 5 alpha(12) value 'ABCDEFGHIJKL'.<br/> 6 <br/> 7 do 12 times varying it-f1 from alpha+0 next alpha+1.<br/> 8 append it.<br/> 9 enddo.<br/>10<br/>11 loop at it.<br/>12 write: / sy-tabix, it-f1.<br/>13 endloop.<br/>14<br/>15 delete it index 5.<br/>16 skip.<br/>17 loop at it.<br/>18 write: / sy-tabix, it-f1.<br/>19 endloop.<br/>20<br/>21 delete it from 6 to 8.<br/>22 skip.<br/>23 loop at it.<br/>24 write: / sy-tabix, it-f1.<br/>25 endloop.<br/>26<br/>27 delete it where f1 between 'B' and 'D'.<br/>28 skip.<br/>29 loop at it.<br/>30 write: / sy-tabix, it-f1.<br/>31 endloop.<br/>32<br/>33 loop at it where f1 between 'E' and 'J'.<br/>34 delete it.<br/>35 endloop.<br/>36<br/>37 skip.<br/>38 loop at it.<br/>39 write: / sy-tabix, it-f1.<br/>40 endloop.<br/>41<br/>42 read table it with key f1 = 'K' binary search.<br/>43 write: /, / 'sy-subrc=', sy-subrc, 'sy-tabix=', sy-tabix, / ''.<br/>44 if sy-subrc = 0.<br/>45 delete it index sy-tabix.<br/>46 endif.<br/>47<br/>48 skip.<br/>49 loop at it.<br/>50 write: / sy-tabix, it-f1.<br/>51 endloop.<br/>52<br/>53 free it.
The code in Listing 12.9 produces this output:
1 1 A<br/> 2 B<br/> 3 C<br/> 4 D<br/> 5 E<br/> 6 F<br/> 7 G<br/> 8 H<br/> 9 I<br/> 10 J<br/> 11 K<br/> 12 L<br/><br/> 1 A<br/> 2 B<br/> 3 C<br/> 4 D<br/> 5 F<br/> 6 G<br/> 7 H<br/> 8 I<br/> 9 J<br/> 10 K<br/> 11 L<br/><br/> 1 A<br/> 2 B<br/> 3 C<br/> 4 D<br/> 5 F<br/> 6 J<br/> 7 K<br/> 8 L<br/><br/> 1 A<br/> 2 F<br/> 3 J<br/> 4 K<br/> 5 L<br/><br/> 1 A<br/> 2 K<br/> 3 L<br/><br/>sy-subrc= 0 sy-tabix= 2<br/><br/> 1 A<br/> 2 L
- Lines 7 through 9 fill it with 12 rows containing the values 'A' through 'L'.
- Lines 11 through 13 write out the contents of the internal table.
- Line 15 deletes the fifth row, removing 'E' from the table. The sixth row becomes the fifth, the seventh becomes the sixth, and so on.
- Line 21 deletes the sixth through eighth rows, removing G, H, and I from the table. The ninth row becomes the sixth, and so on.
- Line 27 deletes rows that have f1 values between 'B' and 'D', inclusive. This causes the second, third and fourth rows to be deleted.
- Line 33 retrieves rows having an f1 value between 'E' and 'J', inclusive. Rows 2 and 3 meet the criteria. The delete statement on line 34 doesn’t have any additions, so it deletes the current row on each pass of the loop. This causes the second and third rows to be deleted.
- Line 42 locates the row having an f1 value of 'K'. Although it only contains three rows, binary search is included for the sake of good example. Row 2 matches, so sy-subrc is set to zero and sy-tabix is set to 2.
- Line 45 is executed because sy-subrc is zero. It deletes row 2, removing 'K' from the internal table.
Like inserts, deletes inside of a loop at it do not affect the internal table immediately, but instead become effective on the next loop pass. When deleting a row after the current row, the table is re-indexed at the endloop, sy-tabix is incremented, and the next loop pass processes the row pointed to by sy-tabix. For example, suppose you are in the third loop pass and you delete row 4. When endloop is executed, the row is deleted, row 5 becomes row 4, and so on. sy-tabix is incremented by 1 and the next loop pass processes the next record.
If, when inside a loop, you delete a row before the current row, the table is again re-indexed at the endloop. This time, however, sy-tabix is incremented by 1 minus the number or rows deleted before the current row. The next time through the loop, the row following the current row is processed. Suppose, for example, in the third loop pass you delete row 3. At the endloop, row 4 becomes row 3, and so on. sy-tabix is incremented by 0, giving 3. Row 4 was re-indexed to 3, so it is processed on the next loop pass.
Creating Top 10 Lists Using append sorted by
Imagine that you are asked to create a report of the top 10 sales representatives in your company. Assuming you have a way of obtaining the total sales for each rep, you could do one of the following:
- Append all reps and their total sales into an internal table.
- Sort them descending by sales.
- Write out the first 10.
This seems like a logical way to proceed. However, using the append sorted by statement often can produce the same result and be twice as efficient.
Syntax for the append sorted by Statement
The following is the syntax for the append sorted by statement.
1 append [<i>wa</i> to] <i>it</i> sorted by <i>c</i>.
where:
- it is the name of an internal table.
- wa is a work area having the same structure as a row of the internal table.
- c is a component of it.
The following points apply:
- If wa to is not specified, the row to be appended is taken from the header line.
- If wa to is specified, the row to be appended is taken from the work area wa.
- Only one component c can be specified.
The append sorted by statement takes a row from the work area and inserts it into the internal table at the point where it belongs in the sort order. It has two unusual properties:
- The number of rows that can be appended is limited by the value on the occurs clause. For example, if the occurs clause is 10, a maximum of 10 rows can be appended to the internal table. This is the only situation where occurs limits the number of rows that can be added to an internal table.
- It only sorts in descending order.
The net effect is a “top n list,” where n is the number on the occurs clause.
With each append, the system searches the existing table contents to determine where the new row fits. The sort order is by c descending. If there are fewer rows in the internal table than specified by n on the occurs clause, the row is as per the sort order. If there are n rows in the internal table, the row is inserted as per the sort order and the last row is discarded. If the value in c already exists in the internal table, the new row is always appended after existing rows that have the same value. Therefore, if occurs is 3 and row 3 contains 'X' in c, a new row having 'X' in c will not be appended.
Listing 12.10 shows a sample program that creates a list of the top three sales reps.
Listing 12.10 Using append sorted by to Find the Top Three Sales Reps
1 1 report ztx1210.<br/> 2 data: begin of it occurs 3,<br/> 3 sales type p decimals 2,<br/> 4 name(10),<br/> 5 end of it.<br/> 6 <br/> 7 it-sales = 100.<br/> 8 it-name = 'Jack'.<br/> 9 append it sorted by sales.<br/>10<br/>11 it-sales = 50.<br/>12 it-name = 'Jim'.<br/>13 append it sorted by sales.<br/>14<br/>15 it-sales = 150.<br/>16 it-name = 'Jane'.<br/>17 append it sorted by sales.<br/>18<br/>19 it-sales = 75.<br/>20 it-name = 'George'.<br/>21 append it sorted by sales.<br/>22<br/>23 it-sales = 200.<br/>24 it-name = 'Gina'.<br/>25 append it sorted by sales.<br/>26<br/>27 it-sales = 100.<br/>28 it-name = 'Jeff'.<br/>29 append it sorted by sales.<br/>30<br/>31 loop at it.<br/>32 write: / it-sales, it-name.<br/>33 endloop.
The code in Listing 12.10 produces this output:
1 200.00 Gina <br/> 150.00 Jane <br/> 100.00 Jack
- Lines 2 through 5 define an internal table with an occurs value of 3. If this internal table is filled using append sorted by, the maximum number of rows in this internal table will be limited to three.
- Lines 7 and 8 assign values to the header line.
- Line 9 searches it for the correct spot to insert the new row. The internal table is empty, so the row is simply appended (see Figure 12.1).
Figure 12.1 : No rows exist in the internal table, so the first row is simply appended. - 50 comes after 100 when sorting sales descending, so line 13 inserts the new row after the existing one (see Figure 12.2).
Figure 12.2 : The second row is inserted in the correct sort sequence so that it comes after the first row. - 150 comes before 100, so line 15 inserts the new row before the first row. The internal table now contains the maximum number of rows: three rows (see Figure 12.3).
Figure 12.3 : This time the sort sequence dictates that the new row be inserted before the first. - 75 comes after 100, so line 21 inserts the new row after the second row, thereby making the new row the third row. The third row would become the fourth, but it can only hold three rows, so the fourth is discarded (see Figure 12.4).
Figure 12.4 : This row fits after the second, so it is inserted there. The internal table can hold a maximum of three rows, so the fourth row is discarded. - 200 comes before 150, so line 25 inserts it before the first row. The rest of the rows are pushed down and the last is discarded (see Figure 12.5).
Figure 12.5 : This time the new row should come first. The existing rows are pushed down and the last one is discarded. - 100 comes after 150, but there is already a 100 there. Line 29 therefore tries to insert the new row after the existing value of 100. That would make it row 4, so the row is not inserted at all (see Figure 12.6).
Figure 12.6 : This new row will follow all existing rows that have the same value. That would make it row 4, so it is not inserted.
Do not mix append sorted by with any other statements that add data to an internal table (such as insert or append). If you fill it with append sorted by, that should be the only statement you use. Mixing these statements will result in unpredictable behavior.
TIP |
|
Filling an Internal Table Using collect
Using the collect statement, you can create totals within an internal table as you fill it.
Syntax for the collect Statement
The following is the syntax for the collect statement.
1 collect [<i>wa</i> into] <i>it</i>.
where:
- it is an internal table.
- wa is a work area that has the same structure as it.
The following points apply:
- If wa into is specified, the row to be collected is taken from the explicit work area wa. In this case, the header line of the internal table is ignored, if it has one.
- If wa into is not specified, the internal table must have a header line. The row to be collected is taken from the header line for it.
When collect is executed, the system forms a key from the default key fields in the work area. The default key fields are the character fields (types c, n, d, t, and x). Therefore the key is composed of the values from all fields of type c, n, d, t, and x. It doesn’t matter if they are beside one another or separated from each other by other fields.
The system then searches the body of the internal table for a row that has the same key as the key in the work area. If it doesn’t find one, the row is appended to the end of the table. If it does find one, the numeric fields (types i, p, and f) in the work area are added to the corresponding fields in the found row. Listing 12.11 illustrates this concept.
Listing 12.11 collect Combines Rows as They Are Added to an Internal Table
1 1 report ztx1211.<br/>2 data: begin of it occurs 10,<br/>3 date type d, " part of default key<br/>4 tot_sales type p decimals 2, "not part of default key<br/> 5 name(10), " part of default key<br/> 6 num_sales type i value 1, "not part of default key<br/> 7 end of it.<br/> 8 <br/> 9 it-date = '19980101'.<br/>10 it-tot_sales = 100.<br/>11 it-name = 'Jack'.<br/>12 collect it.<br/>13<br/>14 it-date = '19980101'.<br/>15 it-tot_sales = 200.<br/>16 it-name = 'Jim'.<br/>17 collect it.<br/>18<br/>19 it-date = '19980101'.<br/>20 it-tot_sales = 300.<br/>21 it-name = 'Jack'.<br/>22 collect it.<br/>23<br/>24 it-date = '19980101'.<br/>25 it-tot_sales = 400.<br/>26 it-name = 'Jack'.<br/>27 collect it.<br/>28<br/>29 it-date = '19980101'.<br/>30 it-tot_sales = 500.<br/>31 it-name = 'Jim'.<br/>32 collect it.<br/>33<br/>34 it-date = '19980101'.<br/>35 it-tot_sales = 600.<br/>36 it-name = 'Jane'.<br/>37 collect it.<br/>38<br/>39 it-date = '19980102'.<br/>40 it-tot_sales = 700.<br/>41 it-name = 'Jack'.<br/>42 collect it.<br/>43<br/>44 loop at it.<br/>45 write: / it-date, it-tot_sales, it-name, it-num_sales.<br/>46 endloop.
The code in Listing 12.11 produces this output:
1 19980101 800.00 Jack 3<br/>19980101 700.00 Jim 2<br/>19980101 600.00 Jane 1<br/>19980102 700.00 Jack 1
- Lines 2 through 7 define an internal table that has four components. Two are character types (date and name) and two are numeric types (tot_sales and num_sales). The default key is therefore composed of the components date and name.
- Lines 9 through 11 assign values to the header line components date, tot_sales, and name. num_sales still has a default value of 1, assigned on line 6.
- Line 12 searches the body of it for a row that has the same values in date and name (the default key fields) as those in the header line. The internal table is empty, so no rows match. The header line is therefore appended to the internal table (see Figure 12.7).
Figure 12.7 : If the default key is not found in the body, the row is appended. The default key is composed of all non-numeric fields, so in this diagram it is the combination of date (first field) and name (third field). - Line 17 behaves like line 12. The internal table has one row, but the values in the date and name fields don’t match, so the header line is appended to the internal table (see Figure 12.8).
Figure 12.8 : Again, the default key is not found in the table, so this row is also appended. - Line 22 searches the internal table for a row that has '19980101' in the date field and 'Jack' in the name field. Row 1 matches, so the numeric fields are added together. The header line tot_sales field contains 200. This is added to the tot_sales field in row 1, yielding a total of 300. The value in the num_sales field in the header line is also added to the num_sales field in row 1, giving a value of 2. Row 1 is updated with these values. The contents of the header line are unchanged (see Figure 12.9).
Figure 12.9 : This time the default key matches the first row of the table. The numeric fields in the work area are added to the corresponding fields in the first row. - Line 27 searches for a row with a date of '19980101' and a name of 'Jack'. Row 1 matches, so the contents of the numeric fields (tot_sales and num_sales) in the header line are added to the numeric fields in the found row (see Figure 12.10).
Figure 12.10: Again, the default key matches the first row of the table. The numeric fields in the work area are added to the corresponding fields in the first row. - Line 32 matches on row 2 and adds '500' to tot_sales and 1 to num_sales (see Figure 12.11).
Figure 12.11: This time the default key matches the second row of the table. The numeric fields in the work area are added to the corresponding fields in the second row. - On line 37, the values in date and name (the default key fields) of the header line do not match any rows in it, so a new row is appended to the end of the table (see Figure 12.12).
Figure 12.12: The default key does not match any rows this time, so a new row is appended. - Line 42 also causes a new row to be appended to the internal table because the values in date and name do not match in any rows of it (see Figure 12.13).
Figure 12.13: The default keys again do not match any rows, so another row is appended.
CAUTION |
|
Summary
- The table body operator provides an efficient way to test for existence of data, to compare two internal tables for equality, or to duplicate an internal table.
- The describe table statement places the number of internal table rows into sy-tfill, the width of a row in bytes into sy-tleng, and the size of the occurs clause into sy-toccu.
- To copy a portion of an internal table from one to another, use append lines of or insert lines of.
- editor-call displays the contents of an internal table in an editor. It enables the user to modify the data, and is also a useful debugging tool.
- insert inserts a row at any position into an internal table. The position can be specified using an index or it can operate on the current row inside a loop.
- modify modifies the contents of one or more rows. The row can be specified using an index or it can operate on the current row inside a loop. Using the where clause, you can modify the contents of many rows.
- delete removes one or more rows. When used inside of a loop without additions, it deletes the current row. You can also specify a single index, an index range, or a where clause.
- clear it clears the header line of it. If there is no header line, all rows are deleted. clear it[] always deletes all rows from it. The internal table memory remains allocated.
- refresh always deletes all rows and leaves the memory allocated. It is exactly equivalent to clear it[]. It is used if the internal table will be refilled with data.
- free it deletes all rows from it and frees the memory. It should be placed in the program immediately after internal table processing is complete.
- Use append sorted by to create top 10 lists instead of appending row by row and then sorting.
- Use collect to accumulate counts and totals within an internal table as it is being filled. It can also be used to ensure that all entries are unique.
DO use the free statement at the end of your program for all internal tables. This explicitly frees memory that will no longer be used while the user views the output. | DON’T append or insert lines one at a time if they can processed as a group using insert lines of or append lines of. |
DO use the table body operator to test for the existence of data. | |
DO use the append sorted by statement when creating top 10 lists, unless the list already exists and only needs to be sorted. |
Q&A
In this chapter you have covered so many ways to accomplish similar tasks. In ABAP/4 there always seems to be many ways to do the same thing. I’m just learning. I can only remember so many ways of doing something. Why not just show me the best way and forget the rest? | |
I appreciate your concern. Wherever possible I leave out archaic, inefficient, rarely used, and duplicate methods. But there are two very good reasons for including the variations I have described here: 1) efficiency and 2) understanding of existing code. Due to the amount of data that resides in an R/3 system, efficiency is a primary concern in ABAP/4 programs. You should strive to use the most efficient form of each statement in a given situation. This can result in drastic performance improvements not only for your programs, but also for the entire system. It is common to have to rewrite code after it reaches production because it impacts system performance. As for the second point, programmers often spend more time reading existing code than creating new code, so you need to understand the subtle variations of these statements. They are used in abundance in SAP code. If you don’t understand SAP’s code, you won’t be able to understand how the data got to its present state or how the output is arrived at. |
Workshop
The Workshop provides you two ways for you to affirm what you’ve learned in this chapter. The Quiz section poses questions to help you solidify your understanding of the material covered and the Exercise section provides you with experience in using what you have learned. You can find answers to the quiz questions and exercises in Appendix B, “Answers to Quiz Questions and Exercises.”
Quiz
- If I modify the value of sy-tabix inside a loop, does this change the current row? For example, would the insert, modify, and delete statements operate on the row in the work area or the row indicated by sy-tabix?
- When would I use the value of sy-toccu? Why would I need to know the value of the occurs clause at runtime?
Exercise 1
Read the contents of ztxlfa1 into an internal table (use select into table). Then modify the land1 column so that the third row contains ‘US’ (use modify transporting where). Also modify the regions, changing all MA to TX (use modify transporting where).