ABAP LOOP AT Statement: Iterating and Processing Internal Tables

Category
ABAP-Statements
Published
Author
Johannes

The LOOP AT statement is one of the most important control structures in ABAP for processing internal tables. It allows you to sequentially iterate through all or selected rows of an internal table, accessing each individual row to read, modify or delete it.

Syntax

The basic syntax of the LOOP AT statement offers various variants for accessing table rows:

1. LOOP with Work Area (INTO)

LOOP AT <internal_table> INTO <work_area>
[WHERE <condition>]
[FROM <index1>] [TO <index2>].
" Statement block
" <work_area> contains a copy of the current row
ENDLOOP.

2. LOOP with Field Symbol (ASSIGNING)

LOOP AT <internal_table> ASSIGNING <field_symbol>
[WHERE <condition>]
[FROM <index1>] [TO <index2>].
" Statement block
" <field_symbol> points directly to the current row (no copying)
ENDLOOP.

3. LOOP with Data Reference (REFERENCE INTO)

LOOP AT <internal_table> REFERENCE INTO <data_reference>
[WHERE <condition>]
[FROM <index1>] [TO <index2>].
" Statement block
" <data_reference> contains a pointer to the current row
ENDLOOP.

4. LOOP without Row Access (Counting Only)

LOOP AT <internal_table> TRANSPORTING NO FIELDS
[WHERE <condition>].
" Statement block (e.g., only use sy-tabix)
ENDLOOP.

Components

  • <internal_table>: The table whose rows should be iterated.
  • INTO <work_area>: The content of the current row is copied into the work area. Changes to the work area do not automatically affect the table.
  • ASSIGNING <field_symbol>: The field symbol points directly to the current row in the table. Changes to the field symbol immediately change the table row.
  • REFERENCE INTO <data_reference>: A data reference pointing to the current row. Access via dereferencing (->*).
  • WHERE <condition>: Filters the rows to iterate. Only rows meeting the condition are processed.
  • FROM <index1>: Starts the loop from the specified index position (only for index tables).
  • TO <index2>: Ends the loop at the specified index position (only for index tables).
  • TRANSPORTING NO FIELDS: No field contents are transported. Useful for counting or when only sy-tabix is needed.

System Fields During the Loop

Within a LOOP AT, important system fields are set:

  • sy-tabix: Contains the current row index of the currently processed row (for standard tables and sorted tables). For hash tables, sy-tabix is not defined (value 0).
  • sy-subrc: After ENDLOOP, sy-subrc = 0 if at least one row was processed. sy-subrc = 4 if no row met the conditions (empty table or WHERE without matches).

Functionality

  1. The LOOP AT statement begins with the first row (or the first matching row with WHERE/FROM).
  2. At each iteration, the current row is provided via the chosen access mechanism (INTO, ASSIGNING, REFERENCE INTO).
  3. The statement block between LOOP AT and ENDLOOP is executed once for each matching row.
  4. After the last row (or when no more rows match), the loop ends and the program continues after ENDLOOP.

Variants and Additions

WHERE Condition

With WHERE, rows can be filtered so only certain rows are iterated:

LOOP AT lt_orders INTO ls_order WHERE status = 'OPEN'.
" Only process open orders
ENDLOOP.

The WHERE condition supports:

  • Comparison operators: =, <>, <, >, <=, >=
  • Logical combinations: AND, OR, NOT
  • Range checks: BETWEEN, IN (for ranges)
  • Pattern matching: CP, NP (for strings)

FROM and TO (Index-Based)

For standard tables and sorted tables, the range can be restricted:

" Only process rows 5 to 10
LOOP AT lt_data INTO ls_data FROM 5 TO 10.
" ...
ENDLOOP.
" From row 100 to end
LOOP AT lt_data INTO ls_data FROM 100.
" ...
ENDLOOP.

GROUP BY (Grouping)

From ABAP 7.40, rows can be grouped during the loop:

LOOP AT lt_orders INTO ls_order
GROUP BY ( customer = ls_order-customer_id
size = GROUP SIZE )
INTO DATA(group).
" Group processing
LOOP AT GROUP group INTO DATA(member).
" Individual members of the group
ENDLOOP.
ENDLOOP.

INTO vs. ASSIGNING vs. REFERENCE INTO

The choice of access mechanism affects performance and functionality:

VariantCopy?ChangesPerformanceUse Case
INTOYesRequires MODIFYSlowerRead only, no changes
ASSIGNINGNoDirectFasterRead and/or modify
REFERENCE INTONoVia ->*FasterWhen reference is needed

Recommendation

  • Read only without changes: ASSIGNING (more performant than INTO)
  • Read and modify: ASSIGNING (changes take effect immediately)
  • Pass reference: REFERENCE INTO
  • Copy explicitly desired: INTO

Examples

1. Simple LOOP with INTO

TYPES: BEGIN OF ty_material,
matnr TYPE matnr,
maktx TYPE maktx,
menge TYPE i,
END OF ty_material.
DATA: lt_materials TYPE STANDARD TABLE OF ty_material,
ls_material TYPE ty_material.
" Fill table (sample data)
lt_materials = VALUE #(
( matnr = 'MAT001' maktx = 'Screw M6' menge = 100 )
( matnr = 'MAT002' maktx = 'Nut M6' menge = 200 )
( matnr = 'MAT003' maktx = 'Washer M6' menge = 150 )
).
" Output all materials
LOOP AT lt_materials INTO ls_material.
WRITE: / sy-tabix, ':', ls_material-matnr, ls_material-maktx.
ENDLOOP.

2. LOOP with ASSIGNING and Value Change

FIELD-SYMBOLS: <fs_material> TYPE ty_material.
" Increase all quantities by 10%
LOOP AT lt_materials ASSIGNING <fs_material>.
<fs_material>-menge = <fs_material>-menge * '1.1'.
ENDLOOP.
" Changes are immediately effective in lt_materials!

3. LOOP with WHERE Condition

DATA: lv_total TYPE i VALUE 0.
" Only sum materials with quantity > 100
LOOP AT lt_materials INTO ls_material WHERE menge > 100.
lv_total = lv_total + ls_material-menge.
ENDLOOP.
WRITE: / 'Total quantity (>100):', lv_total.
IF sy-subrc <> 0.
WRITE: / 'No materials with quantity > 100 found.'.
ENDIF.

4. LOOP with REFERENCE INTO

DATA: lr_material TYPE REF TO ty_material.
LOOP AT lt_materials REFERENCE INTO lr_material.
" Access via dereferencing
lr_material->menge = lr_material->menge + 50.
ENDLOOP.

5. Delete Rows in LOOP

" Remove rows with quantity = 0
LOOP AT lt_materials ASSIGNING <fs_material>.
IF <fs_material>-menge = 0.
DELETE lt_materials.
ENDIF.
ENDLOOP.

Note: Deleting rows within a LOOP is allowed. The loop correctly continues with the next row. See also DELETE for more variants.

6. LOOP with FROM/TO for Pagination

CONSTANTS: lc_page_size TYPE i VALUE 10.
DATA: lv_page TYPE i VALUE 2,
lv_from TYPE i,
lv_to TYPE i.
lv_from = ( lv_page - 1 ) * lc_page_size + 1.
lv_to = lv_page * lc_page_size.
LOOP AT lt_materials INTO ls_material FROM lv_from TO lv_to.
" Process rows 11-20 (page 2)
WRITE: / ls_material-matnr.
ENDLOOP.

7. TRANSPORTING NO FIELDS for Counting

DATA: lv_count TYPE i VALUE 0.
LOOP AT lt_materials TRANSPORTING NO FIELDS WHERE menge > 100.
lv_count = lv_count + 1.
ENDLOOP.
WRITE: / 'Number of materials with quantity > 100:', lv_count.

Tip: For pure counting, the REDUCE function or lines() with FILTER is often more elegant:

DATA(lv_count) = REDUCE i( INIT count = 0
FOR wa IN lt_materials WHERE ( menge > 100 )
NEXT count = count + 1 ).

Distinction from Other Statements

LOOP vs. READ TABLE

  • LOOP AT: Iterates through multiple/all rows sequentially.
  • READ TABLE: Reads a single, specific row (by key or index).

For accessing a single row, READ TABLE is more performant:

" Single row by key
READ TABLE lt_materials INTO ls_material WITH KEY matnr = 'MAT001'.
" Single row by index
READ TABLE lt_materials INTO ls_material INDEX 1.

LOOP vs. FOR Expression

From ABAP 7.40, there is the FOR expression for inline iterations:

" Create new table with filtered data
DATA(lt_filtered) = VALUE ty_materials(
FOR wa IN lt_materials WHERE ( menge > 100 )
( wa )
).

LOOP AT remains the preferred choice for complex processing logic with multiple statements.

Loop Control

Within a LOOP AT, the following statements can control the loop:

  • CONTINUE: Jumps to the next iteration (skips the rest of the current iteration).
  • EXIT: Immediately ends the loop and continues after ENDLOOP.
  • CHECK: Ends the current iteration if the condition is false (like IF NOT ... CONTINUE).
LOOP AT lt_materials ASSIGNING <fs_material>.
" Skip materials without text
CHECK <fs_material>-maktx IS NOT INITIAL.
" Abort at special material
IF <fs_material>-matnr = 'STOP'.
EXIT.
ENDIF.
" Processing...
ENDLOOP.

Performance Tips

  1. ASSIGNING instead of INTO: Avoids copying data and is significantly faster for large structures.

  2. Use WHERE condition: Filters the rows to process and reduces the number of iterations.

  3. Secondary keys: For frequent WHERE queries on specific fields, a secondary key can improve performance. See also SORT for preparing binary searches.

  4. PARALLEL CURSOR: When processing two sorted tables with a relationship, the parallel cursor technique can drastically improve performance:

DATA: lv_tabix TYPE sy-tabix VALUE 1.
LOOP AT lt_header INTO ls_header.
LOOP AT lt_items INTO ls_item FROM lv_tabix.
IF ls_item-header_id <> ls_header-id.
lv_tabix = sy-tabix.
EXIT.
ENDIF.
" Process item...
ENDLOOP.
ENDLOOP.
  1. Avoid nested LOOPs without index: Two nested loops over large tables without optimization lead to O(n²) complexity.

Important Notes / Best Practice

  • LOOP AT is fundamental for working with internal tables in ABAP. Load data first with SELECT from the database.
  • Prefer ASSIGNING for better performance and direct write access.
  • Use WHERE conditions to process only relevant rows.
  • Never forget the closing ENDLOOP.
  • Check sy-subrc after the loop if you need to know whether rows were processed.
  • For hash tables, sy-tabix is not available – use your own counters if needed.
  • For modern ABAP development (from 7.40), check if FOR expressions or REDUCE are more suitable for your use case.