Internal Tables
ABAP Developmentbeginner

Internal Tables Part 4: READ TABLE, sy-subrc and Table Expressions

Key takeaway

Read single rows correctly: READ TABLE by index, by key and with TABLE KEY, TRANSPORTING NO FIELDS for existence checks, sy-subrc and sy-tabix — and the modern table expressions with OPTIONAL and DEFAULT.

Explanation

📌 KEY POINTS
✅ READ TABLE … INDEX n / WITH KEY … / WITH TABLE KEY … reads one row; check sy-subrc (0 found, 4 not found).

✅ TRANSPORTING NO FIELDS checks existence without copying data.

✅ A failed READ leaves the work area unchanged — never use it without checking sy-subrc.

💡 Modern: itab[ key = x ] raises CX_SY_ITAB_LINE_NOT_FOUND; use OPTIONAL/DEFAULT or line_exists( ).

━━━━━━━━━━━━━━━━━━━━
▶ WHERE WE ARE

Parts 1–3 introduced tables and access techniques. Reading one specific row is the most frequent operation — and a frequent source of bugs.

━━━━━━━━━━━━━━━━━━━━
▶ 1. READ BY INDEX

READ TABLE gt_flight INTO gs_flight INDEX 1.

Only for standard and sorted tables (hashed tables have no index).

━━━━━━━━━━━━━━━━━━━━
▶ 2. READ BY KEY

READ TABLE gt_flight INTO gs_flight WITH KEY carrid = 'LH' connid = '0400'.

  • Any fields can be used ("free key").
  • On standard tables this is a linear search unless you add BINARY SEARCH on a correctly sorted table (Part 5).
  • On sorted/hashed tables, WITH TABLE KEY (complete key) uses the optimized access; WITH KEY on the leading key fields of a sorted table is also optimized.

━━━━━━━━━━━━━━━━━━━━
▶ 3. SY-SUBRC AND SY-TABIX

  • sy-subrc = 0 found, 4 not found (8 with BINARY SEARCH and position beyond the end).
  • sy-tabix = index of the found row (standard/sorted), useful for MODIFY … INDEX or as a start index for loops.

━━━━━━━━━━━━━━━━━━━━
▶ 4. EXISTENCE CHECK WITHOUT COPYING

READ TABLE gt_flight TRANSPORTING NO FIELDS WITH KEY carrid = 'LH'.

IF sy-subrc = 0. … ENDIF.

Modern: IF line_exists( gt_flight[ carrid = 'LH' ] ).

━━━━━━━━━━━━━━━━━━━━
▶ 5. TRANSPORTING SPECIFIC FIELDS

READ TABLE gt_flight INTO gs_flight TRANSPORTING price WITH KEY … — copies only selected fields (others in gs_flight stay as they were — clear first!).

━━━━━━━━━━━━━━━━━━━━
▶ 6. TABLE EXPRESSIONS (7.40+)

  • gs_flight = gt_flight[ carrid = 'LH' connid = '0400' ].
  • Not found → exception CX_SY_ITAB_LINE_NOT_FOUND (not sy-subrc!).
  • Safe forms: VALUE #( gt_flight[ … ] OPTIONAL ) (initial if not found), VALUE #( gt_flight[ … ] DEFAULT ls_default ).
  • Index: gt_flight[ 1 ]; field directly: gt_flight[ carrid = 'LH' ]-price.

━━━━━━━━━━━━━━━━━━━━
▶ STEP BY STEP

Run the code example: read by index, by key, check existence, and see how an unchecked failed READ keeps old data in the work area.

✅ CHECKPOINT: every READ in your code is followed by a correct success check.

Code example

ABAP Code
REPORT zitab_part4. TYPES: BEGIN OF ty_flight,         carrid TYPE s_carr_id,         connid TYPE s_conn_id,         fldate TYPE s_date,         price  TYPE s_price,       END OF ty_flight. DATA: gt_flight TYPE STANDARD TABLE OF ty_flight,      gs_flight TYPE ty_flight. START-OF-SELECTION.  SELECT carrid connid fldate price FROM sflight    INTO TABLE gt_flight UP TO 20 ROWS WHERE carrid = 'LH'. * ===== 1. Read by index =====  READ TABLE gt_flight INTO gs_flight INDEX 1.  IF sy-subrc = 0.    WRITE: / 'first row:', gs_flight-connid, gs_flight-fldate.  ENDIF. * ===== 2. Read by key + sy-tabix =====  READ TABLE gt_flight INTO gs_flight WITH KEY connid = '0400'.  IF sy-subrc = 0.    WRITE: / 'connection 0400 found at row', sy-tabix.  ELSE.    WRITE: / 'connection 0400 not found'.  ENDIF. * ===== 3. The classic bug: failed READ keeps old values =====  READ TABLE gt_flight INTO gs_flight WITH KEY connid = '9999'.* WRONG: WRITE gs_flight-price.  -> still the price of connection 0400!  IF sy-subrc <> 0.    CLEAR gs_flight.    WRITE: / 'connection 9999 not found - work area cleared'.  ENDIF. * ===== 4. Existence check without copy =====  READ TABLE gt_flight TRANSPORTING NO FIELDS WITH KEY carrid = 'LH'.  IF sy-subrc = 0.    WRITE: / 'at least one LH flight exists'.  ENDIF. * ===== 5. Read only selected fields =====  CLEAR gs_flight.  READ TABLE gt_flight INTO gs_flight TRANSPORTING price WITH KEY connid = '0400'.  IF sy-subrc = 0.    WRITE: / 'price only:', gs_flight-price.  ENDIF. * 💡 Modern table expressions (7.40+), for reading newer code:*    IF line_exists( gt_flight[ connid = '0400' ] ). ... ENDIF.*    lv_price = gt_flight[ connid = '0400' ]-price.          " exception if missing*    ls_safe  = VALUE #( gt_flight[ connid = '9999' ] OPTIONAL ).   " initial if missing*    Not found -> CX_SY_ITAB_LINE_NOT_FOUND, not sy-subrc.

Real project scenario

An invoice program read the tax rate for each item with READ TABLE and used the work area even when the read failed. For items with a new tax code missing from the lookup table, the previous item's tax rate was applied silently. Finance found wrong tax amounts during month-end reconciliation.
The fix checked sy-subrc after every READ and raised a clear error for unknown tax codes; in later refactoring, table expressions with OPTIONAL and explicit handling made such mistakes impossible to overlook.

Common mistakes

  • Using the work area after a failed READ.
  • Expecting table expressions to set sy-subrc.
  • Linear READ WITH KEY on large standard tables.
  • TRANSPORTING specific fields into a work area that still contains old data.
  • READ INDEX on hashed tables.

Best practices

  • Check sy-subrc immediately after every READ TABLE.
  • Use TRANSPORTING NO FIELDS or line_exists( ) for existence checks.
  • Use WITH TABLE KEY on sorted/hashed tables.
  • Use OPTIONAL/DEFAULT with table expressions or catch the exception.
  • Clear work areas before partial TRANSPORTING reads.

Interview angle

Questions: "What does sy-subrc = 4 mean after READ TABLE?", "What happens to the work area if READ fails?", "How do table expressions behave when no row exists?"
Strong answer: 0 found, 4 not found; a failed READ leaves the work area unchanged, so stale data can be processed; TRANSPORTING NO FIELDS checks existence; table expressions raise CX_SY_ITAB_LINE_NOT_FOUND unless OPTIONAL or DEFAULT is used, and don't set sy-subrc; line_exists( ) is the modern existence check.

Practice this lesson

Quick check

1. After READ TABLE fails with sy-subrc = 4, what does the target work area contain?

2. Which statement checks whether a row exists without copying any data?

3. What occurs when a table expression such as itab[ key = 'X' ] is evaluated and no row matches the specified key?

Interview questions

1. An order-validation loop first calls line_exists( ) and then reads the same row with a table expression. What would you improve?

Answer it in your own words first, then compare.

2. Explain the difference between READ TABLE ... TRANSPORTING NO FIELDS, table expressions itab[ ] and the modern LINE_EXISTS( ) / LINE_INDEX( ).

Answer it in your own words first, then compare.

Practice more with Interview AI →

Reference-verified: the steps are checked against official SAP documentation and tutorials, and object and field names in the sample code are checked for consistency. The code has not been compiled or run on an SAP system by ERPClimb. Syntax marked release-dependent varies by SAP release, so check it in your own system.

More lessons in this topic

Interview questions on this topic

Related SAP topics