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 rowENDLOOP.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 rowENDLOOP.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 onlysy-tabixis 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-tabixis not defined (value 0).sy-subrc: AfterENDLOOP,sy-subrc = 0if at least one row was processed.sy-subrc = 4if no row met the conditions (empty table or WHERE without matches).
Functionality
- The
LOOP ATstatement begins with the first row (or the first matching row withWHERE/FROM). - At each iteration, the current row is provided via the chosen access mechanism (
INTO,ASSIGNING,REFERENCE INTO). - The statement block between
LOOP ATandENDLOOPis executed once for each matching row. - 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 ordersENDLOOP.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 10LOOP AT lt_data INTO ls_data FROM 5 TO 10. " ...ENDLOOP.
" From row 100 to endLOOP 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:
| Variant | Copy? | Changes | Performance | Use Case |
|---|---|---|---|---|
INTO | Yes | Requires MODIFY | Slower | Read only, no changes |
ASSIGNING | No | Direct | Faster | Read and/or modify |
REFERENCE INTO | No | Via ->* | Faster | When reference is needed |
Recommendation
- Read only without changes:
ASSIGNING(more performant thanINTO) - 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 materialsLOOP 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 > 100LOOP 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 = 0LOOP 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 keyREAD TABLE lt_materials INTO ls_material WITH KEY matnr = 'MAT001'.
" Single row by indexREAD 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 dataDATA(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 afterENDLOOP.CHECK: Ends the current iteration if the condition is false (likeIF 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
-
ASSIGNINGinstead ofINTO: Avoids copying data and is significantly faster for large structures. -
Use WHERE condition: Filters the rows to process and reduces the number of iterations.
-
Secondary keys: For frequent WHERE queries on specific fields, a secondary key can improve performance. See also
SORTfor preparing binary searches. -
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.- Avoid nested LOOPs without index: Two nested loops over large tables without optimization lead to O(n²) complexity.
Important Notes / Best Practice
LOOP ATis fundamental for working with internal tables in ABAP. Load data first withSELECTfrom the database.- Prefer
ASSIGNINGfor better performance and direct write access. - Use
WHEREconditions to process only relevant rows. - Never forget the closing
ENDLOOP. - Check
sy-subrcafter the loop if you need to know whether rows were processed. - For hash tables,
sy-tabixis not available – use your own counters if needed. - For modern ABAP development (from 7.40), check if
FORexpressions orREDUCEare more suitable for your use case.