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)
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
lt_status to move
MOVE-CORRESPONDING lt_status TO lt_orders.- 4711 · status B
- 4713 · status C
- Same names: order_id, status
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.
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.
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.
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.
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.
Add your perspective.
Share a question, another approach, or something you have tried.
Checking sign-in…
Loading comments…