SAP BOX

'26/10/11 UPDATE

ABAP / FIELD NOTES

Why Do Existing Rows Disappear After MOVE-CORRESPONDING Between Internal Tables?

MOVE-CORRESPONDING between internal tables does not just fill same-name columns: it deletes the target table and rebuilds it with as many rows as the source. Using a fictional example, this note covers why KEEPING TARGET LINES only appends rows, how CORRESPONDING with a lookup table enriches existing rows by key, and the header line trap.

You want to fill a status into an order table, so you move a status table into it with MOVE-CORRESPONDING. Afterwards the three orders have become two, and every customer and amount is blank. It is a common result when the statement is used on internal tables the way it is used on structures. After reading this you will be able to explain how MOVE-CORRESPONDING between internal tables rebuilds the target table, know what to use to enrich existing rows, and spot places in old code where a header line causes an unintended assignment.

The example uses an order table lt_orders (columns order_id, customer, amount, status) and a status table lt_status (columns order_id, status). lt_orders holds three orders, 4711, 4712 and 4713, without a status, and lt_status holds status B for 4711 and status C for 4713. Order IDs, customers, amounts and the program are invented, and the code was not run on a real system. The results given here are worked out by applying the rules on the pages MOVE-CORRESPONDING and CORRESPONDING, Lookup Table in the ABAP Keyword Documentation (7.58 and 7.50 editions).

Between internal tables, the target is deleted and rebuilt

When MOVE-CORRESPONDING lt_status TO lt_orders. runs, ABAP looks for identically named components in the line types of the two tables, here order_id and status. If there is at least one, the target table lt_orders is deleted first and as many initial rows are inserted as the source lt_status has. The source rows are then read in the same order as in LOOP, and the identically named components of each row are assigned to the new rows.

The result is two rows. 4711 and 4713 get the statuses B and C, but customer is blank and amount is 0.00. Order 4712, which was not in lt_status, is gone altogether. This statement does not find matching rows by order ID and fill in the status. It builds a new target table in the shape of the source table.

SAP NOTES

Moving 2 statuses turned 3 orders into 2

Fictional example: lt_status (order ID, status) moved into lt_orders (order ID, customer, amount, status)

  1. lt_orders before

    lines( lt_orders ) = 3

    • 4711 · CUST-A · 120.00 · no status
    • 4712 · CUST-B · 80.00 · no status
    • 4713 · CUST-C · 45.50 · no status
  2. lt_status to move

    MOVE-CORRESPONDING lt_status TO lt_orders.

    • 4711 · status B
    • 4713 · status C
    • Same names: order_id, status
  3. lt_orders after

    lines( lt_orders ) = 2

    • 4711 · (blank) · 0.00 · B
    • 4713 · (blank) · 0.00 · C
    • Row 4712, customers and amounts gone

Order IDs, customers and amounts are fictional. The result follows from the MOVE-CORRESPONDING rules in the ABAP Keyword Documentation (7.58 and 7.50); it is not a run result.

MOVE-CORRESPONDING between internal tables does not look up rows by order ID and fill in the status. It deletes the target table, creates as many new rows as the source has and fills only the identically named columns.

Why the intuition from structures fails

On structures, the same statement behaves differently. MOVE-CORRESPONDING ls_status TO ls_order. assigns only the identically named components order_id and status and leaves the other components alone, so customer and amount stay as they were. Many developers learn this behaviour first and assume the same for tables: only the same-name columns change and the rest remains. In the table variant, though, what carries over is not the columns but the number of source rows.

The rule has one exception. If the two line types have no identically named component at all, nothing is assigned and the target table is not deleted either. Put the other way round, a single column name that happens to match is enough to delete the target. And if a table is assigned to itself with MOVE-CORRESPONDING, the statement is ignored, so the rows are not deleted and refilled.

SAP NOTES

Structures and internal tables follow different rules

The same MOVE-CORRESPONDING statement, but what happens to the rest of the target depends on the operands

  • Structure to structure

    ls_order-status = ls_status-status

    • Only identically named components
    • Other components are not affected
    • Customer and amount stay as they were
  • Internal table to internal table

    lines( ) 3 → 2

    • The target table is deleted first
    • As many initial rows as the source
    • Each row gets the same-name columns
  • KEEPING TARGET LINES

    lines( ) 3 → 5

    • The existing 3 rows are kept
    • 2 new rows are appended
    • No status goes into existing rows

If no column names match, the target table is not even deleted and stays unchanged. Values follow the documented rules; they are not run results.

Do not carry the intuition from structures over to internal tables. KEEPING TARGET LINES does not merge rows either; it only appends.

KEEPING TARGET LINES appends instead of merging

The addition that stops the target rows from being deleted is KEEPING TARGET LINES. MOVE-CORRESPONDING lt_status TO lt_orders KEEPING TARGET LINES. keeps the existing three rows, appends as many initial rows as the source has and assigns the source to those new rows. The result is five rows. The existing rows 4711, 4712 and 4713 still have no status, and two separate rows for 4711 and 4713, holding only the order ID and the status, are added.

If the target table has a unique key, the appended rows can clash with existing ones. If lt_orders were a sorted table with order_id as its unique key, for example, 4711 would be inserted twice. The documentation says that the corresponding exceptions are raised if uniqueness is violated and that the same runtime errors can occur as for INSERT. The INSERT documentation classifies a duplicate unique key produced while inserting a set of rows as the uncatchable runtime error ITAB_DUPLICATE_KEY, so prevent duplicate keys before appending rather than relying on TRY. The constructor expression itab2 = CORRESPONDING #( BASE ( itab2 ) itab1 ). gives the same result as the statement with KEEPING TARGET LINES, and from the 7.51 documentation on, DISCARDING DUPLICATES can be added to it to drop duplicate rows.

To enrich existing rows, use a lookup table

What was intended in the first place, filling the status into the rows with the same order ID, is done by the lookup table variant of CORRESPONDING. lt_orders = CORRESPONDING tt_order( lt_orders FROM lt_status USING order_id = order_id ). searches lt_status for a row with the same order ID for each row of lt_orders. If one is found, the identically named components are assigned; if not, the row is left as it is. The order_id used for the search is not assigned by default. The result is three rows: 4711 with B, 4712 blank and 4713 with C, with customers and amounts unchanged.

There is one condition. The lookup table must be searched with a sorted key or a hash key. Without KEY, lt_status must be a sorted or hashed table, and the comparison columns must cover the whole key. For a standard table, define a secondary key and name it with USING KEY. This variant has the same rules in the 7.50 and 7.58 editions. If you prefer a familiar pattern, a loop over lt_orders with a field symbol that finds the order ID with READ TABLE lt_status and changes status only when sy-subrc is 0 gives the same result.

SAP NOTES

To fill values into existing rows

Matching rows by order ID is not something MOVE-CORRESPONDING does

  • CORRESPONDING ... FROM

    USING order_id = order_id

    • Looks up lt_status for each lt_orders row
    • If found, same-name columns are assigned
    • 4712, not found, stays unchanged
  • LOOP and READ TABLE

    IF sy-subrc = 0.

    • Loop over lt_orders with a field symbol
    • Read lt_status by order ID
    • Change status only when found
  • When adding rows is the goal

    lines( ) 3 + 2 = 5

    • KEEPING TARGET LINES, or
    • CORRESPONDING #( BASE ( ... ) ... )
    • Unique key duplicates: runtime error

CORRESPONDING ... FROM needs lt_status to be searchable by a sorted or hash key. The example is fictional and was not run.

Enrich existing rows with CORRESPONDING using a lookup table, or with LOOP and READ TABLE. Use KEEPING TARGET LINES or BASE only when appending rows is what you want.

Header lines and releases

MOVE-CORRESPONDING with internal tables as operands arrived in ABAP release 7.40, SP05. Before that, only structures could be used. EXPANDING NESTED TABLES, KEEPING TARGET LINES and the constructor operator CORRESPONDING were added in the same release.

In old programs, check for header lines first. Tables declared WITH HEADER LINE or with DATA BEGIN OF ... OCCURS, SELECT-OPTIONS and TABLES parameters of function modules have a header line: a work area with the same name as the table. If you write only the name of such a table in MOVE-CORRESPONDING, the header line rather than the table body becomes the operand, and a single-row structure assignment takes place. To move the whole table, append [] as in t_status[] to address the body. Header lines are obsolete and cannot be declared in classes.

SAP GUI ABAP Editor showing four numbered markers: MOVE-CORRESPONDING lt_status TO lt_orders with a comment that 2 rows remain with initial customer and amount; with KEEPING TARGET LINES, 3 rows plus 2 new rows giving 5; CORRESPONDING tt_order( lt_orders FROM lt_status USING order_id = order_id ) giving 3 rows with 4711 B, 4712 blank and 4713 C; and, in old code with header lines, t_status[] and t_orders[] addressing the table bodies.
An example editor view collecting three ways of writing it with the same lt_orders and lt_status, plus the header line notation. Each statement is assumed to start separately from the state in the first comment. ZDEMO_MOVE_CORR is a fictional program; the code was not run, and the results in the comments follow from the documented rules.

Read the markers on the screen above as a review checklist. Marker 1 is where the target table is deleted and rebuilt with as many rows as the source. Marker 2 is where KEEPING TARGET LINES appends rows instead of merging them. Marker 3 is the lookup table variant that matches rows by order ID and fills only the status. Marker 4 is the line in old code with header lines that addresses the table bodies with [].

What to check in your code

When you meet MOVE-CORRESPONDING between internal tables, check three things. Does the target table hold rows put there before this statement? Was the intent to keep the values in those rows? Is either operand a table with a header line? If the goal is to enrich existing rows by key, switch to CORRESPONDING with a lookup table or a READ TABLE loop, and use KEEPING TARGET LINES or BASE only when appending rows is the goal.

If you remember only one thing, make it this: MOVE-CORRESPONDING between internal tables does not fill in values; it builds a new target table with as many rows as the source.

THE ENDBack to the library
COMMENTS BOX

Add your perspective.

Share a question, another approach, or something you have tried.

Newest first

Checking sign-in…

Loading comments…