Day 11

Internal Tables


Chapter Objectives

After you complete this chapter, you should be able to:

Internal Table Basics

An internal table is a temporary table stored in RAM on the application server. It is created and filled by a program during execution and is discarded when the program ends. Like a database table, an internal table consists of one or more rows with an identical structure, but unlike a database table, it cannot hold data after the program ends. Use it as temporary storage for manipulating data or as a temporary private buffer.

Definition of an Internal Table

An internal table consists of a body and an optional header line (see Figure 11.1).

The body holds the rows of the internal table. All rows within it have the same structure. The term "internal table" itself usually refers to the body of the internal table.

The header line is a field string with the same structure as a row of the body, but it can only hold a single row. It is a buffer used to hold each record before it is added or each record as it is retrieved from the internal table.

Figure 11.1 shows the definition of an internal table named it.

Figure 11.1 : The definition of an internal table named it is shown at the top of this figure. The header line and body are also shown.

NOTE
In this book, a naming convention is used for internal tables. For simple programs with only a single internal table, the internal table name will usually be it (for internal table). If multiple internal tables exist, the name of each will usually begin with it.

To define an internal table body, use occurs n on the definition of any field string except tables. occurs creates the body of the internal table. The memory for the body is not allocated until the first row is added to it. Without occurs, you only have a field string.

To define an internal table with a header line, you must include either begin of or with header line in the definition. A header line is automatically created if begin of appears in the definition. If you use like instead of begin of, the internal table will not have a header line unless you add with header line after the occurs clause. This is illustrated in lines 2 through 10 of Listing 11.1.

The only time you would create an internal table without a header line is in the case of a nested internal table. A nested internal table cannot have a header line.


Listing 11.1  Basic Ways of Defining Internal Tables with and Without a Header Line

 1 report ztx1101.
 2 data: begin of it1 occurs 10,          "has a header line
 3         f1,
 4         f2,
 5         f3,
 6         end of it1.
 7
 8 data it2 like ztxlfa1 occurs 100.      "doesn't have a header line
 9
10 data it3 like ztxlfa1 occurs 100 with header line. "it does now

The code in Listing 11.1 does not produce any output.

Clearing Up the Main Source of Confusion Surrounding Internal Tables

Figure 11.1 contains a typical internal table definition. It defines two things: the body of an internal table and a header line. Confusion arises because both the body and the header line are named it. it is the name of the body, and it is also the name of the header line. Where you place the name it in your code determines to what you are referring.

When used in an assignment statement, it always refers to the header line. For example, it-f1 = 'A' refers to component f1 of the header line named it. Or in f3 = it-f1, the header line it is also referred to.

Examples of Internal Table Definitions

To define internal tables with and without header lines, use the forms recommended in Listing 11.2.


Listing 11.2  These Definitions Create Internal Tables with and Without a Header Line

 1 report ztx1102.
 2 data: begin of it1 occurs 10,          "has a header line
 3         f1,
 4         f2,
 5         f3,
 6         end of it1.
 7
 8 data it2 like ztxlfa1 occurs 100.      "doesn't have a header line
 9
10 data it3 like ztxlfa1 occurs 100 with header line. "it does now
11
12 data it4 like it3 occurs 100.          "doesn't have a header line
13
14 data     begin of it5 occurs 100.      "has a header line
15 include      structure ztxlfa1.
16 data         end of it5.
17
18 data     begin of it6 occurs 100.      "this is why you might use
19 include      structure ztxlfa1.        "the include statement
20 data:        delflag,
21              rowtotal,
22              end of it6.
23
24 data: begin of it7 occurs 100,         "don't do it this way
25           s like ztxlfa1,              "component names will be
26           end of it7.                  "prefixed with it7-s-
27
28 data it8 like sy-index occurs 10
29     with header line.
30
31 data: begin of it9 occurs 10,
32           f1 like sy-index,
33           end of it9.

The code in Listing 11.2 does not produce any output.

Adding Data to an Internal Table Using the append Statement

To add a single row to a internal table, you can use the append statement. append copies a single row from any work area and places it in the body at the end of the existing rows. The work area can be the header line, or it can be any other field string having the same structure as a row in the body.

Syntax for the append Statement

The following is the syntax for the append statement.

append [wa to] [initial line to] it.

where:

The following points apply:

The statement append it to it appends the header line named it to the body named it. The statement append it does the same thing, because the default work area is the header line. Being more succinct, the latter is usually used.

A work area mentioned explicitly in the append statement is known as an explicit work area. Any field string having the same structure as a row of the internal table can be used as an explicit work area. If a work area is not mentioned, the implicit work area (the header line) is used.

The statement append initial line to it appends a row containing initial values (blanks and zeros) to the internal table. It is the same as executing the following two statements in succession: clear it and append it.

Listing 11.3 shows a sample program that appends three rows to an internal table.


Listing 11.3  This Program Adds Three Rows to Internal Table it from the Header Line

 1 report ztx1103.
 2 data: begin of it occurs 3,
 3           f1(1),
 4           f2(2),
 5           end of it.
 6 it-f1 = 'A'.
 7 it-f2 = 'XX'.
 8 append it to it.    "appends header line IT to body IT
 9 write: / 'sy-tabix =', sy-tabix.
10 it-f1 = 'B'.
11 it-f2 = 'YY'.
12 append it.          "same as line 8
13 write: / 'sy-tabix =', sy-tabix.
14 it-f1 = 'C'.
15 append it.          "the internal table now contains three rows.
16 write: / 'sy-tabix =', sy-tabix.

The code in Listing 11.3 produces this output:

sy-tabix =              1
sy-tabix =          2
sy-tabix =          3

NOTE
In actuality, your Basis consultant sets a limit on the maximum amount of extended memory an internal table can allocate. If you exceed that amount, your program will allocate private memory from the work process and it will no longer be able to roll your program out. This makes the work process unavailable for use by other programs until your program has completely finished processing. To avoid this problem, you should use an extract instead.

Using the occurs Addition

occurs does not limit the number of rows that can be added to the internal table. For example, if you specify occurs 10, you can put more than 10 rows into the internal table. The number of rows you can put into an internal table is theoretically only limited by the amount of virtual memory available on the application server.

The system uses the occurs clause only as a guideline to determine how much memory to allocate. The first time a row is added to the internal table, enough memory is allocated to hold the number of rows specified on the occurs clause. If you use that memory up, more is allocated as needed.

Alternatively, you can specify occurs 0. If you do this, the system allocates 8KB pages of memory at a time. However, there are no advantages to using occurs 0 other than the fact it is only a little easier to code occurs 0 than it is to estimate the size of the internal table.

NOTE
Don't use occurs 0 if you expect to store less than 8KB in an internal table. If you do, the system will allocate 8KB from the paging area. Memory will be wasted and paging could increase, resulting in poorer performance.

For peak performance and minimum wasted memory, choose an occurs value equal to the average maximum number of rows in the table. For example, if most of the time the internal table is filled with a maximum of 100 rows, but every once in a while it is filled with a maximum of 1,000 rows, set the occurs value to 100.

Depending on the occurs clause and the size of the internal table, the system will allocate memory from either the program roll area or the system paging area, or both. Memory accesses in the roll area can be slightly faster than accesses in the paging area. Allocations in the paging area are always one page in size (usually 8KB, or 8,192 bytes).

There are two methods that the system uses to perform allocations. In the first, occurs is non-zero, and the size of the internal table (calculated from occurs * number of bytes per row) is less than or equal to 8KB. (The number of bytes per row can be obtained using the describe table statement detailed in the next chapter, or via the Field view in the debugger.) When the first row is added to the internal table, memory is allocated from the program roll area. The amount allocated is equal to the calculated size of the internal table. If this amount is exceeded, an equal amount is allocated and the process is repeated until the total exceeds 8KB. When this happens, subsequent allocations obtain 8KB pages from the paging area.

If you specify occurs 0, all allocations are done in the paging area, causing one 8KB page to be allocated at a time. If the calculated size of the internal table is greater than 8KB, the system changes the occurs value to zero when the first allocation is done and all allocations are satisfied from the paging area. You can see the change to occurs by using the describe table statement after the first allocation and displaying the value of sy-toccu. This statement is described on Day 9, "Assignments, Conversions, and Calculations."

Reading Data from an Internal Table

Two statements are commonly used to read the data from an internal table:

Use loop at to read multiple rows from the internal table. Use read table to read a single row.

Reading Multiple Rows Using the loop at Statement

To read some or all rows from an internal table, you can use the loop at statement. Loop at reads the contents of the internal table, placing them one at a time into a work area.

Syntax for the loop at Statement
The following is the syntax for the loop at statement.
   loop at it [into wa] [from m] [to n] [where exp].
    ---
   endloop.
where: The rows are read from the internal table one at a time and placed in succession into the work area. The lines of code between the loop at and endloop are executed for each row retrieved. The loop finishes automatically when the last row has been read, and the statement following the endloop is then executed.
The following points apply: The from, to, and where additions can be mixed at will.
Within the loop, sy-tabix contains the relative row number of the current record. For example, while processing the first record in the internal table, the value of sy-tabix will be 1. While processing the second, sy-tabix will be 2. Upon exiting the loop, the value of sy-tabix is reset to the value it had when the loop began. If loops are nested, the value in sy-tabix relates to the current loop.
After endloop, sy-subrc will be zero if any rows were read. It will be non-zero if no rows were read from the internal table.
Listing 11.4 expands on Listing 11.3, looping at and writing out the rows of the internal table.


Listing 11.4  This Program Adds 3 Rows to Internal Table it from the Header Line, and Then Writes Them Back out Again

        1 report ztx1104.
        2 data: begin of it occurs 3,
        3           f1(1),
        4           f2(2),
        5           end of it.
        6 it-f1 = 'A'.
        7 it-f2 = 'XX'.
        8 append it to it.    "appends header line IT to body IT
        9 it-f1 = 'B'.
       10 it-f2 = 'YY'.
       11 append it.          "same as line 8
       12 it-f1 = 'C'.
       13 append it.          "the internal table now contains three rows.
       14 sy-tabix = sy-subrc = 99.
       15 loop at it.         "same as: loop at it into it
       16     write: / sy-tabix, it-f1, it-f2.
       17     endloop.
       18 write: / 'done. sy-tabix =', sy-tabix,
       19        / '      sy-subrc =', sy-subrc.

The code in Listing 11.4 produces this output:

         1  A XX
            2  B YY
            3  C YY
   done. sy-tabix =         99
       sy-subrc =      0

Restricting the Rows Read from the Internal Table
Using the from, to, and where additions, you can restrict the number of rows read from the internal table. Listing 11.5 expands on Listing 11.4, looping at the internal table four times. Each time it writes out only certain rows.


Listing 11.5  This Program Is Like Listing 11.4, but Only Some of the Rows Are Read

        1 report ztx1105.
        2 data: begin of it occurs 3,
        3           f1(1),
        4           f2(2),
        5           end of it.
        6 it-f1 = 'A'.
        7 it-f2 = 'XX'.
        8 append it.
        9 it-f1 = 'B'.
       10 it-f2 = 'YY'.
       11 append it.
       12 it-f1 = 'C'.
       13 append it.                  "it now contains three rows
       14
       15 loop at it where f2 = 'YY'. "f2 is right, it-f2 would be wrong here
       16     write: / sy-tabix, it-f1, it-f2.
       17     endloop.
       18 skip.
       19
       20 loop at it to 2.            "same as: loop at it from 1 to 2.
       21     write: / sy-tabix, it-f1, it-f2.
       22     endloop.
       23 skip.
       24
       25 loop at it from 2.          "same as: loop at it from 2 to 3.
       26     write: / sy-tabix, it-f1, it-f2.
       27     endloop.
       28 skip.
       29
       30 loop at it from 2 where f1 = 'C'.
       31     write: / sy-tabix, it-f1, it-f2.
       32     endloop.

The code in Listing 11.5 produces this output:

        2  B YY
         3  C YY

         1  A XX
         2  B YY

         2  B YY
         3  C YY

        3  C YY

CAUTION
Although the where returns a subset of the table contents, a full table scan is always performed. Caution

If you make sure the data type and length of the field in exp matches the internal table field exactly, no conversions will be performed. This causes your loop to run more quickly. If conversion is required, it is performed on every loop pass and this can slow processing down considerably. Use like or constants to avoid conversion.

Using exit, continue, stop, and check
Table 11.1 illustrates the effects of exit, continue, and check when used within a loop at/endloop construct.

Table 11.1  Statements that Can Alter Loop Processing for Internal Tables
Statement
Effect
exitTerminates the loop immediately. Processing continues at the statement immediately following endloop.
ContinueGoes immediately to the endloop statement, bypassing all following statements within the loop. The next row is returned from the internal table and processing continues from the top of the loop. If there are no more rows to retrieve, processing continues at the first statement following endloop.
Check exp If exp is true, processing continues as if this statement had not been executed. If exp is false, its effect is the same as continue.

Reading a Single Row Using the read table Statement

To locate and read a single row from an internal table, use read table. It reads a single row that matches specific criteria and places it in a work area.

Syntax for the read table Statement
The following is the syntax for the read table statement.
read table it [into wa] [index i | with key keyexp [binary search] ] [comparing cmpexp] [transporting texp].
where:

The following points apply:

Using the index Addition

An internal table row's index is its relative row number. For example, the first row in the table is index 1, the second is index 2, and so on. On the read table statement, if index i is specified, the system retrieves the ith row from the internal table and places it into the work area. For example, read table it index 7 reads the seventh row from the internal table and places it in the header line.
If the read was successful (that is, if the ith row exists), sy-subrc is set to zero and sy-tabix is set to i (see Listing 11.6).


Listing 11.6  The index Addition on the read table Statement Locates a Single Row by Its Relative Row Number

     1 report ztx1106.
     2 data: begin of it occurs 3,
     3           f1(2) type n,
     4           f2    type i,
     5           f3(2) type c,
     6           f4    type p,
     7           end of it,
     8       wa like it.
     9
    10 it-f1 = '10'. it-f3 = 'AA'. it-f2 = it-f4 = 1. append it.
    11 it-f1 = '20'. it-f3 = 'BB'. it-f2 = it-f4 = 2. append it.
    12 it-f1 = '30'. it-f3 = 'CC'. it-f2 = it-f4 = 3. append it.
    13
    14 read table it index 2.
    15 write: / 'sy-subrc =', sy-subrc,
    16        / 'sy-tabix =', sy-tabix,
    17        / it-f1, it-f2, it-f3, it-f4.
    18
    19 read table it into wa index 1.
    20 write: /,
    21        / 'sy-subrc =', sy-subrc,
    22        / 'sy-tabix =', sy-tabix,
    23        / it-f1, it-f2, it-f3, it-f4,
    24        / wa-f1, wa-f2, wa-f3, wa-f4.
    25
    26 read table it index 4.
    27 write: /,
    28        / 'sy-subrc =', sy-subrc,
    29        / 'sy-tabix =', sy-tabix,
    30        / it-f1, it-f2, it-f3, it-f4,
    31        / wa-f1, wa-f2, wa-f3, wa-f4.

The code in Listing 11.6 produces this output:

    sy-subrc =     0
    sy-tabix =          2
    20          2  BB               2

    sy-subrc =     0
    sy-tabix =          1
    20          2  BB               2
    10          1  AA               1

    sy-subrc =     4
    sy-tabix =          0
    20          2  BB               2
    10          1  AA               1

Using the with key Addition
If with key keyexp is specified, the system finds a row that matches the key expression and places it in the header line. Table 11.2 describes key expressions and their effects. Using a key expression, you can specify a single row to be retrieved. If more than one row matches the expression, the first one found (the one with the lowest index) is returned.

Table 11.2  Key Expressions and Their Effects
Key Expression
Effect
c1 = v1 c2 = v2 ...Locates the first row in the internal table where component c1 has the value v1 and component c2 has the value v2, and so on. v1 is a literal, constant, or variable.
(f1) = v1 (f2) = v2 ...Same as above, but f1 is a variable that contains the name of the component to be compared. The value in f1 must be in uppercase. If f1 is blank, the comparison is ignored.
= wawa is a work area identical in structure to an internal table row. This key expression locates the first row in the internal table that is exactly equal to the contents of wa. Blanks are treated as values to be found; they do not match any value other than blanks.
Wawa is a work area identical to or shorter than the structure of the internal table. If wa has n fields, the fields of wa match the first n fields of an internal table row. This key expression locates the first row in the internal table whose first n fields match the contents of wa. Blanks are treated as values to be found; they do not match any value other than blanks.

NOTE
In release 4, conversions necessary for the first three key expressions in Table 11.2 are performed with the same order of precedence as that used for logi-cal expressions. In systems prior, conversions were performed by converting from the value on the right to the data type and length of the component on the left.

Table 11.3 describes the values of sy-subrc and sy-tabix after a read table it with key... has executed.

Table 11.3  Values Assigned to SY-SUBRC and SY-TABIX
Result
sy-subrc
sy-tabix
Read was successful (a matching row was found)
0
index of matching row
Read unsuccessful, but a row with a key greater than the one requested exists
4
index of row with next higher key
Read unsuccessful, and no rows found having a higher key
8
number of rows in it + 1

Listing 11.7 illustrates the use of key expressions.


Listing 11.7  Using a Key Expression, You Can Search for a Row by Specifying a Value Instead of an Index

     1 report ztx1107.
     2 data: begin of it occurs 3,
     3           f1(2) type n,
     4           f2    type i,
     5           f3(2) type c,
     6           f4    type p,
     7           end of it,
     8       begin of w1,
     9           f1 like it-f1,
    10           f2 like it-f2,
    11           end of w1,
    12       w2 like it,
    13       f(8).
    14
    15 it-f1 = '10'. it-f3 = 'AA'. it-f2 = it-f4 = 1. append it.
    16 it-f1 = '20'. it-f3 = 'BB'. it-f2 = it-f4 = 2. append it.
    17 it-f1 = '30'. it-f3 = 'CC'. it-f2 = it-f4 = 3. append it.
    18
    19 read table it with key f1 = '30' f2 = 3.
    20 write: / 'sy-subrc =', sy-subrc,
    21        / 'sy-tabix =', sy-tabix,
    22        / it-f1, it-f2, it-f3, it-f4.
    23
    24 f = 'F2'.                                 "must be in uppercase
    25 read table it into w2 with key (f) = 2.
    26 write: /,
    27        / 'sy-subrc =', sy-subrc,
    28        / 'sy-tabix =', sy-tabix,
    29        / it-f1, it-f2, it-f3, it-f4,
    30        / w2-f1, w2-f2, w2-f3, w2-f4.
    31
    32 clear w2.
    33 w2-f1 = '10'. w2-f3 = 'AA'. w2-f2 = w2-f4 = 1.
    34 read table it with key = w2.
    35 write: /,
    36        / 'sy-subrc =', sy-subrc,
    37        / 'sy-tabix =', sy-tabix,
    38        / it-f1, it-f2, it-f3, it-f4.
    39
    40 w1-f1 = '20'. w1-f2 = 2.
    41 read table it into w2 with key w1.
    42 write: /,
    43        / 'sy-subrc =', sy-subrc,
    44        / 'sy-tabix =', sy-tabix,
    45        / it-f1, it-f2, it-f3, it-f4.

The code in Listing 11.7 produces this output:

    sy-subrc =     0
    sy-tabix =          3
    30          3  CC               3
    
    sy-subrc =     0
    sy-tabix =          2
    30          3  CC               3
    20          2  BB               2
    
    sy-subrc =     0
    sy-tabix =          1
    10          1  AA               1

    sy-subrc =     0
    sy-tabix =          2
    10          1  AA               1

Using the binary search Addition

Whenever you use the with key addition, you should also use the binary search addition, which causes the row to be located using a binary search algorithm instead of a linear table scan. This results in the same performance gains as those achieved when searching a database table via an index. Beforehand, the table must be sorted in ascending order by the components specified in the key expression (see the following section on sorting).
CAUTION
Only blanks in a default key field will match all values. This means that you cannot clear types d, t, n, and x and obtain a match-clearing will set them to zeros, not blanks. You must force blanks into these fields for them to match. You can do this using a field string (see the following example), using a subfield, or using a field symbol (see the previous section on field symbols for more information).

No Additions
If neither an index nor a key expression are specified, the table is scanned from the beginning for a row that matches the default key contained in the header line. The default key is an imaginary key composed of all character fields in the header line (types c, d, t, n, and x). A blank value in a default key column causes all values in that column to match. Afterward, the values of sy-subrc and sy-tabix are set they same way as they are after a read table using a key expression.
Listing 11.8 provides an example.


Listing 11.8  This Program Finds a Row Having the Same Values as the Default Key Fields in the Header Line. Blanks in a Default Key Field Cause a Column to be Ignored.

     1 report ztx1108.
      2 data: begin of it occurs 3,
      3           f1(2) type n,   "character field -     part of default key
      4           f2    type i,   "numeric   field - not part of default key
      5           f3(2) type c,   "character field -     part of default key
      6           f4    type p,   "numeric   field - not part of default key
      7           end of it.
      8
      9 it-f1 = '10'. it-f3 = 'AA'. it-f2 = it-f4 = 1. append it.
     10 it-f1 = '20'. it-f3 = 'BB'. it-f2 = it-f4 = 2. append it.
     11 it-f1 = '30'. it-f3 = 'CC'. it-f2 = it-f4 = 3. append it.
     12
     13 sort it by f1 f3.
     14 clear it.
     15 it(2) = ' '. it-f3 = 'BB'.
     16 read table it binary search.
     17 write: / 'sy-subrc =', sy-subrc,
     18        / 'sy-tabix =', sy-tabix,
     19        / 'f1=', it-f1, 'f2=', it-f2, 'f3=', it-f3, 'f4=', it-f4.
     20
     21 clear it.
     22 it-f1 = '30'. it-f3 = 'AA'.
     23 read table it binary search.
     24 write: / 'sy-subrc =', sy-subrc,
     25        / 'sy-tabix =', sy-tabix,
     26        / 'f1=', it-f1, 'f2=', it-f2, 'f3=', it-f3, 'f4=', it-f4.

The code in Listing 11.8 produces this output:
     sy-subrc =     0
     sy-tabix =          2
     f1= 20 f2=          2  f3= BB f4=               2
     sy-subrc =     4
     sy-tabix =          3
     f1= 30 f2=          0  f3= AA f4=               0

In this example, the internal table only contains a few rows, so binary search would not produce a measurable improvement in performance. It is only included to illustrate how it should be used.
Using the comparing Addition
comparing detects differences between the contents of the work area and a row that was found before it is placed in the work area. Use it in conjunction with index or with key. If, after a row has been found, the work area contents are the same as the found row, sy-subrc will be 0. If the contents are different, sy-subrc will be 2 and the contents will be overwritten by the found row. If the row is not found, sy-subrc will be > 2 and the contents will remain unchanged.
Table 11.4 describes the values for the comparison expression (cmpexp in the syntax for read table).

Table 11.4  Forms for the Comparison Expression in the Read Table Statement
Cmpexp
Description
f1 f2 ...After a row is found, the value of f1 in the found row is compared with the value of f1 in the work area. Then the value of f2 is compared with the value of f2 in the work area, and so on. If they are all equal, sy-subrc is set to 0. If any are different, sy-subrc is set to 2.
all fieldsAll fields are compared, as described for f1 f2....
no fieldsNo fields are compared. This is the default.

Listing 11.9 provides examples.


Listing 11.9  The comparing Addition Sets the Value of sy-subrc to 2 Whenever Fields Differ

     1 report ztx1109.
     2 data: begin of it occurs 3,
     3           f1(2) type n,
     4           f2    type i,
     5           f3(2) type c,
     6           f4    type p,
     7           end of it,
     8       wa like it.
     9
    10 it-f1 = '10'. it-f3 = 'AA'. it-f2 = it-f4 = 1. append it.
    11 it-f1 = '20'. it-f3 = 'BB'. it-f2 = it-f4 = 2. append it.
    12 it-f1 = '30'. it-f3 = 'CC'. it-f2 = it-f4 = 3. append it.
    13
    14 read table it index 2 comparing f1.
    15 write: / 'sy-subrc =', sy-subrc,
    16        / 'sy-tabix =', sy-tabix,
    17        / it-f1, it-f2, it-f3, it-f4.
    18
    19 read table it into wa index 1 comparing f2 f4.
    20 write: /,
    21        / 'sy-subrc =', sy-subrc,
    22        / 'sy-tabix =', sy-tabix,
    23        / it-f1, it-f2, it-f3, it-f4,
    24        / wa-f1, wa-f2, wa-f3, wa-f4.
    25
    26 it = wa.
    27 read table it with key f3 = 'AA' comparing all fields.
    28 write: /,
    29        / 'sy-subrc =', sy-subrc,
    30        / 'sy-tabix =', sy-tabix,
    31        / it-f1, it-f2, it-f3, it-f4,
    32        / wa-f1, wa-f2, wa-f3, wa-f4.

The code in Listing 11.9 produces this output:
    sy-subrc =     2
    sy-tabix =          2
    20          2  BB               2

    sy-subrc =     2
    sy-tabix =          1
    20          2  BB               2
    10          1  AA               1
    
    sy-subrc =     0
    sy-tabix =          1
    10          1  AA               1
    10          1  AA               1

NOTE
The read table statement can only be used to read internal tables. It doesn't work with database tables. Use select single instead.

Using the transporting Addition
transporting affects how fields are moved from the found row to the work area. If it is specified, only the values of the specified components are moved to the work area. If a row is not found, transporting does nothing.
Table 11.5 describes the values for the transporting expression (texp in the syntax for read table).

Table 11.5  Forms for the Transporting Expression in the READ TABLE Statement
Cmpexp
Description
f1 f2 ...After a row is found, the value of f1 in the found row overlays the value of f1 in the work area. Then the value of f2 overlays the value of f2 in the work area, and so on. Only the components named after transporting are moved. All other components remain unchanged.
All fieldsAll fields are transported. This is the default, and has the same effect as leaving off the transporting addition.
no fieldsNo fields are transported. None of the fields in the work area are changed.

This addition is useful if you only want to test for the existence of a row in an internal table without disturbing the contents of the header line. For example, before appending a row, you might want to determine whether the row already exists in the internal table. Listing 11.10 provides an example.

Listing 11.10  The Most Efficient Way to Insert Rows into a Sorted Internal Table While Maintaining the Sort Order.

     1 report ztx1110.
     2 data: begin of it occurs 3,
     3           f1(2) type n,
     4           f2    type i,
     5           f3(2) type c,
     6           f4    type p,
     7           end of it.
     8
     9 it-f1 = '40'. it-f3 = 'DD'. it-f2 = it-f4 = 4. append it.
    10 it-f1 = '20'. it-f3 = 'BB'. it-f2 = it-f4 = 2. append it.
    11
    12 sort it by f1.
    13 do 5 times.
    14     it-f1 = sy-index * 10.
    15     it-f3 = 'XX'.
    16     it-f2 = it-f4 = sy-index.
    17     read table it
    18         with key f1 = it-f1
    19         binary search
    20         transporting no fields.
    21     if sy-subrc <> 0.
    22         insert it index sy-tabix.
    23         endif.
    24     enddo.
    25
    26 loop at it.
    27     write: / it-f1, it-f2, it-f3, it-f4.
    28     endloop.

The code in Listing 11.10 produces this output:
    10          1  XX               1
    20          2  BB               2
    30          3  XX               3
    40          4  DD               4
    50          5  XX               5

Sorting the Contents of an Internal Table

To sort the contents of an internal table, use the sort statement. Rows can be sorted by one or more columns in ascending or descending order. The sort sequence itself can also be modified.

Syntax for the sort Statement

The following is the syntax for the sort statement.

sort it [descending] [as text] [by f1 [ascending|descending] [as text] 
     f2 ...].

where:

The following points apply:

The sort order for rows that have the same value is not predictable. Rows having the same value in a sorted column can appear in any order after the sort. Listing 11.11 shows examples of the sort statement and also illustrates this point.


Listing 11.11  Use the sort Statement to Reorder the Rows of an Internal Table

 1 report ztx1111.
 2 data: begin of it occurs 5,
 3           i like  sy-index,
 4           t,
 5           end of it,
 6       alpha(5) value 'CBABB'.
 7
 8 do 5 times varying it-t from alpha+0 next alpha+1.
 9     it-i = sy-index.
10     append it.
11     enddo.
12
13 loop at it.
14     write: / it-i, it-t.
15     endloop.
16
17 skip.
18 sort it by t.
19 loop at it.
20     write: / it-i, it-t.
21     endloop.
22
23 skip.
24 sort it by t.
25 loop at it.
26     write: / it-i, it-t.
27     endloop.
28
29 skip.
30 sort it by t i.
31 loop at it.
32     write: / it-i, it-t.
33     endloop.
34
35 skip.
36 sort it by t descending i.
37 *same as: sort it descending by t i ascending.
38 loop at it.
39     write: / it-i, it-t.
40     endloop.
41
42 skip.
43 sort it.
44 *same as: sort it by t.
45 loop at it.
46     write: / it-t.
47     endloop.

The code in Listing 11.11 produces this output:

         1  C
         2  B
         3  A
         4  B
         5  B

         3  A
         2  B
         4  B
         5  B
         1  C

         3  A
         5  B
         4  B
         2  B
         1  C

         3  A
         2  B
         4  B
         5  B
         1  C

         1  C
         2  B
         4  B
         5  B
         3  A

    A
    B
    B
    B
    C

Sort Order and the as text Addition

Internally within the operating system, each character you see on the screen is represented by a numeric value. During a sort, the character's numeric value determines the resulting order. For example, when an ABAP/4 program runs on an ASCII platform, the letter o has an ASCII decimal value of 111, and p is 112. Therefore, p comes after o in the sort sequence. This sort sequence is called the binary sort sequence.

When a language contains accented characters, there is a numeric value assigned to represent each accented form of a character. For example, o and ö (o with an umlaut) are distinct and separate characters, each with an individual numeric value. (In ASCII, the value of ö is decimal 246.) When you sort data containing accented characters, the accented forms should be appear with the non-accented forms. For example, for example, o and ö should be together, and then p. However, the binary values of the accented and non-accented characters do not follow each other in numeric sequence. Therefore, a way is needed to change the sort order so that accented characters are sorted correctly.

The as text addition modifies the sort order so that accented characters are sorted correctly. With as text, the binary sort sequence is not used. Instead, the text environment determines the sort sequence.

The text environment is a set of characteristics associated with the user's logon language. It is determined by the language code you enter when you log on, and consists primarily of the language's character set and collating sequence. You can also change the text environment at runtime using the set locale statement. This statement sets the value of sy-langu, the current character set and collating sequence to the language specified.

The following points apply to the as text addition:

Listing 11.12 provides an example.


Listing 11.12  Sorting Accented Characters Requires the Use of the as text Addition

 1 report ztx1112.
 2 data: begin of it occurs 4,
 3           t(30),
 4           end of it.
 5
 6 it-t = 'Higgle'.     append it.
 7 it-t = 'Hoffman'.    append it.
 8 it-t = 'Höllman'.    append it.
 9 it-t = 'Hubble'.     append it.
10
11 write: / 'sy-langu=', sy-langu.
12 sort it. "sorts by default key. t is type c, therefore sorts by t.
13 loop at it.
14     write: / it-t.
15     endloop.
16
17 skip.
18 set locale language 'D'. "Equivalent to signing on in German
19 write: / 'sy-langu=', sy-langu.
20 sort it as text.         "as text here applies to all type c components
21 *same as: sort it by t as text.
22 loop at it.
23     write: / it-t.
24     endloop.

The code in Listing 11.12 produces this output:

   sy-langu= E
   Higgle
   Hoffman
   Hubble
   Höllman
   
   sy-langu= D
   Higgle
   Hoffman
   Höllman
   Hubble

CAUTION
After sorting as text, do not use read table with the addition binary search. The rows will not be sorted in binary order, so a binary search will yield incorrect results. To use binary search successfully, see the ABAP/4 keyword documentation on the convert into sortable code statement.

Sort sequences vary with platforms. When transporting from one operating system to another, the only guaranteed sort sequences are A-Z, a-z, and 0-9, but not necessarily in that order.

TIP
After sorting, you can delete duplicates from an internal table using the delete adjacent duplicates statement, described in the ABAP/4 keyword documentation.

Summary

DO
DON'T
DO use the binary search addition on the read table statement. It will increase the performance of the search tremendously. DON'T use occurs 0 for internal tables smaller than 8KB. This results in over-allocation of memory and slower performance.
DO use the index addition on the read table statement whenever possible. It is the fastest way to locate a single row.  

Q&A

Q
In some programs, I've seen a user-defined type that has an occurs clause. The type is then used to define an internal table type and subsequently an internal table, like that shown in Listing 11.13. Why do they do it this way? Can't you always define the internal table with the data statement? Why introduce the types statement?


Listing 11.13  Defining an Internal Table with a User-Defined Type

   1  report ztx1113.
   2  types: begin of my_type,
   3             f1,
   4             f2,
   5             end of my_type,
   6         t_it type my_type occurs 10.
   7  data it type t_it.

A
There is no advantage to using internal table types in the way shown in Listing 11.13. Types are useful only if you use them to define more than one data object. In this listing, only one data object is defined of the type t_it. It would be simpler in this case to do away with the types statements and create the entire definition using data.
Theoretically, types are useful if you need to define multiple data objects that are the same. Listing 11.14 shows three ways of defining multiple internal tables: using data only, using types, and using a DDIC structure.


Listing 11.14  Defining Multiple Internal Tables with types Simplifies the Definitions

    1 report ztx1113.
    2
    3 * Define 3 identical internal tables using DATA only
    4 data: begin of it_1a occurs 10,
    5           f1,
    6           f2,
    7           end of it_1a,
    8       it_1b like it_1a occurs 10 with header line,
    9       it_1c like it_1a occurs 10 with header line.
   10
   11 * Define 3 more identical internal tables using TYPES
   12 types: begin of t_,
   13            f1,
   14            f2,
   15            end of t_,
   16       t_it type t_ occurs 10.
   17 data: it_2a type t_it,
   18       it_2b type t_it,
   19       it_2c type t_it.
   20
   21 * Define 3 more using a DDIC structure
   22 data: it_3a like ztx_it occurs 10 with header line,
   23       it_3b like ztx_it occurs 10 with header line,
   24       it_3c like ztx_it occurs 10 with header line.

Of the first two methods, it is a matter of opinion which is clearer; neither one appears to have much of an advantage over the other. I believe the third method, however, to be the preferred one. It is clearer, and to see the definition, you can simply double-click the DDIC structure name. When viewing the structure, what you will see is much more meaningful than an ABAP/4 definition; there will be short text for each data element and one for the structure itself. These texts can also be translated. In addition, the structure is available for re-use within multiple programs. In my opinion, using a structure wins hands-down over the use of a types definition.
There is only one thing that a type can do that a structure can't: It can contain the definition for a nested internal table. Only in that case would I use a type. In all other cases, a data begin of or a like a structure in the DDIC is the way to go.

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 Questions

  1. Who sets a limit on the maximum amount of extended memory an internal table can allocate?
  2. Why shouldn't you use occurs 0 if you expect to store less than 8KB in an internal table?
  3. Can you use the read table statement to read database tables?

Exercise 1

Display and explain the conversions that occur in program ztx1110 (see Listing 11.15).


Listing 11.15  Conversions (Hint: Program->Analysis)

     1 report ztx1110.
     2 data: begin of it occurs 3,
     3           f1(2) type n,
     4           f2    type i,
     5           f3(2) type c,
     6           f4    type p,
     7           end of it.
     8
     9 it-f1 = '40'. it-f3 = 'DD'. it-f2 = it-f4 = 4. append it.
    10 it-f1 = '20'. it-f3 = 'BB'. it-f2 = it-f4 = 2. append it.
    11
    12 sort it by f1.
    13 do 5 times.
    14     it-f1 = sy-index * 10.
    15     it-f3 = 'XX'.
    16     it-f2 = it-f4 = sy-index.
    17     read table it
    18         with key f1 = it-f1
    19         binary search
    20         transporting no fields.
    21     if sy-subrc <> 0.
    22         insert it index sy-tabix.
    23         endif.
    24     enddo.
    25
    26 loop at it.
    27     write: / it-f1, it-f2, it-f3, it-f4.
    28     endloop.