The FOR expression enables inline iteration within constructor expressions like VALUE, REDUCE and NEW. It replaces many LOOP AT ... APPEND constructs with compact, functional syntax.
Syntax
1. FOR … IN (Table Iteration)
FOR <variable> IN <table> [ INDEX INTO <index> ] [ WHERE ( <condition> ) ]2. FOR … UNTIL/WHILE (Conditional Iteration)
FOR <variable> = <start_value> [ THEN <expression> ] UNTIL <condition>FOR <variable> = <start_value> [ THEN <expression> ] WHILE <condition>3. FOR GROUPS (Grouping)
FOR GROUPS <group> OF <variable> IN <table> GROUP BY <grouping_expression>Basic Principle
FOR is used within VALUE, REDUCE or NEW:
" Create table from another tableDATA(lt_result) = VALUE ty_result_tab( FOR ls_source IN lt_source ( field1 = ls_source-field1 field2 = ls_source-field2 )).Examples
1. Simple Table Transformation
TYPES: BEGIN OF ty_person, id TYPE i, name TYPE string, age TYPE i, END OF ty_person, ty_persons TYPE TABLE OF ty_person WITH EMPTY KEY.
TYPES: ty_names TYPE TABLE OF string WITH EMPTY KEY.
DATA: lt_persons TYPE ty_persons.
lt_persons = VALUE #( ( id = 1 name = 'Max' age = 30 ) ( id = 2 name = 'Anna' age = 25 ) ( id = 3 name = 'Peter' age = 35 )).
" Extract only namesDATA(lt_names) = VALUE ty_names( FOR ls_person IN lt_persons ( ls_person-name )).
" Result: Max, Anna, Peter2. Comparison: FOR vs. LOOP
" === CLASSIC WITH LOOP ===DATA: lt_names_classic TYPE ty_names.
LOOP AT lt_persons INTO DATA(ls_p). APPEND ls_p-name TO lt_names_classic.ENDLOOP.
" === MODERN WITH FOR ===DATA(lt_names_modern) = VALUE ty_names( FOR ls_p IN lt_persons ( ls_p-name )).3. FOR with WHERE (Filtering)
" Only adults (age >= 18)DATA(lt_adults) = VALUE ty_persons( FOR ls_person IN lt_persons WHERE ( age >= 18 ) ( ls_person )).
" More complex conditionDATA(lt_filtered) = VALUE ty_persons( FOR ls_person IN lt_persons WHERE ( age >= 25 AND name <> 'Max' ) ( ls_person )).4. Transformation with Calculation
TYPES: BEGIN OF ty_product, id TYPE i, name TYPE string, price TYPE p DECIMALS 2, quantity TYPE i, END OF ty_product.
TYPES: BEGIN OF ty_order_line, product_id TYPE i, total TYPE p DECIMALS 2, END OF ty_order_line, ty_order_lines TYPE TABLE OF ty_order_line WITH EMPTY KEY.
DATA: lt_products TYPE TABLE OF ty_product.
lt_products = VALUE #( ( id = 1 name = 'Widget' price = '10.00' quantity = 5 ) ( id = 2 name = 'Gadget' price = '25.00' quantity = 3 ) ( id = 3 name = 'Gizmo' price = '15.00' quantity = 8 )).
" Calculate order lines with total priceDATA(lt_order_lines) = VALUE ty_order_lines( FOR ls_prod IN lt_products ( product_id = ls_prod-id total = ls_prod-price * ls_prod-quantity )).5. INDEX INTO – Read Row Index
TYPES: BEGIN OF ty_numbered, position TYPE i, name TYPE string, END OF ty_numbered, ty_numbered_tab TYPE TABLE OF ty_numbered WITH EMPTY KEY.
DATA(lt_numbered) = VALUE ty_numbered_tab( FOR ls_person IN lt_persons INDEX INTO lv_idx ( position = lv_idx name = ls_person-name )).
" Result:" position = 1, name = 'Max'" position = 2, name = 'Anna'" position = 3, name = 'Peter'6. Nested FOR (Cartesian Product)
TYPES: ty_colors TYPE TABLE OF string WITH EMPTY KEY, ty_sizes TYPE TABLE OF string WITH EMPTY KEY.
TYPES: BEGIN OF ty_variant, color TYPE string, size TYPE string, END OF ty_variant, ty_variants TYPE TABLE OF ty_variant WITH EMPTY KEY.
DATA: lt_colors TYPE ty_colors, lt_sizes TYPE ty_sizes.
lt_colors = VALUE #( ( `Red` ) ( `Blue` ) ( `Green` ) ).lt_sizes = VALUE #( ( `S` ) ( `M` ) ( `L` ) ).
" Create all combinationsDATA(lt_variants) = VALUE ty_variants( FOR lv_color IN lt_colors FOR lv_size IN lt_sizes ( color = lv_color size = lv_size )).
" Result: 9 combinations (3x3)" Red-S, Red-M, Red-L, Blue-S, Blue-M, ...7. FOR … UNTIL (Conditional Iteration)
TYPES: ty_numbers TYPE TABLE OF i WITH EMPTY KEY.
" Generate numbers 1 to 10DATA(lt_1_to_10) = VALUE ty_numbers( FOR i = 1 UNTIL i > 10 ( i )).
" With THEN for step sizeDATA(lt_even) = VALUE ty_numbers( FOR i = 2 THEN i + 2 UNTIL i > 20 ( i ))." Result: 2, 4, 6, 8, 10, 12, 14, 16, 18, 208. FOR … WHILE
" Square numbers under 100DATA(lt_squares) = VALUE ty_numbers( FOR n = 1 WHILE n * n < 100 ( n * n ))." Result: 1, 4, 9, 16, 25, 36, 49, 64, 819. FOR GROUPS – Grouping
TYPES: BEGIN OF ty_sale, region TYPE string, amount TYPE p DECIMALS 2, END OF ty_sale, ty_sales TYPE TABLE OF ty_sale WITH EMPTY KEY.
DATA: lt_sales TYPE ty_sales.
lt_sales = VALUE #( ( region = 'NORTH' amount = '1000.00' ) ( region = 'SOUTH' amount = '2000.00' ) ( region = 'NORTH' amount = '1500.00' ) ( region = 'EAST' amount = '800.00' ) ( region = 'SOUTH' amount = '1200.00' )).
TYPES: BEGIN OF ty_region_total, region TYPE string, total TYPE p DECIMALS 2, END OF ty_region_total, ty_region_totals TYPE TABLE OF ty_region_total WITH EMPTY KEY.
" Sum per regionDATA(lt_by_region) = VALUE ty_region_totals( FOR GROUPS <group> OF ls_sale IN lt_sales GROUP BY ls_sale-region ( region = <group> total = REDUCE p DECIMALS 2( INIT sum = CONV p DECIMALS 2( 0 ) FOR m IN GROUP <group> NEXT sum = sum + m-amount ) )).
" Result:" NORTH: 2500.00" SOUTH: 3200.00" EAST: 800.0010. FOR GROUPS with Multiple Grouping Fields
TYPES: BEGIN OF ty_order, year TYPE i, month TYPE i, category TYPE string, amount TYPE p DECIMALS 2, END OF ty_order.
DATA: lt_orders TYPE TABLE OF ty_order.
lt_orders = VALUE #( ( year = 2024 month = 1 category = 'A' amount = 100 ) ( year = 2024 month = 1 category = 'A' amount = 150 ) ( year = 2024 month = 1 category = 'B' amount = 200 ) ( year = 2024 month = 2 category = 'A' amount = 300 )).
TYPES: BEGIN OF ty_group_key, year TYPE i, month TYPE i, END OF ty_group_key.
" Group by year and monthDATA(lt_monthly) = VALUE ty_region_totals( FOR GROUPS <grp> OF ls_ord IN lt_orders GROUP BY ( year = ls_ord-year month = ls_ord-month ) ( region = |{ <grp>-year }/{ <grp>-month }| total = REDUCE p DECIMALS 2( INIT s = CONV p DECIMALS 2( 0 ) FOR m IN GROUP <grp> NEXT s = s + m-amount ) )).11. LET for Local Variables
TYPES: BEGIN OF ty_display, id TYPE i, display TYPE string, END OF ty_display, ty_displays TYPE TABLE OF ty_display WITH EMPTY KEY.
DATA(lt_display) = VALUE ty_displays( FOR ls_person IN lt_persons LET prefix = 'ID: ' suffix = COND #( WHEN ls_person-age >= 30 THEN ' (Senior)' ELSE '' ) IN ( id = ls_person-id display = |{ prefix }{ ls_person-id } - { ls_person-name }{ suffix }| )).12. FOR in REDUCE
" Sum of all amountsDATA(lv_total) = REDUCE p DECIMALS 2( INIT sum = CONV p DECIMALS 2( 0 ) FOR ls_sale IN lt_sales NEXT sum = sum + ls_sale-amount).
" Filter with WHEREDATA(lv_north_total) = REDUCE p DECIMALS 2( INIT sum = CONV p DECIMALS 2( 0 ) FOR ls_sale IN lt_sales WHERE ( region = 'NORTH' ) NEXT sum = sum + ls_sale-amount).13. FOR in NEW (Data References)
" Create table as referenceDATA(lr_names) = NEW ty_names( FOR ls_person IN lt_persons ( ls_person-name )).
LOOP AT lr_names->* INTO DATA(lv_name). WRITE: / lv_name.ENDLOOP.14. Extend Existing (BASE)
DATA: lt_existing TYPE ty_names.
lt_existing = VALUE #( ( `Existing1` ) ( `Existing2` ) ).
" Add new entriesDATA(lt_combined) = VALUE ty_names( BASE lt_existing FOR ls_person IN lt_persons ( ls_person-name )).
" Result: Existing1, Existing2, Max, Anna, Peter15. Complex Transformation with CORRESPONDING
TYPES: BEGIN OF ty_source, kunnr TYPE string, name1 TYPE string, ort01 TYPE string, END OF ty_source,
BEGIN OF ty_target, customer_id TYPE string, customer_name TYPE string, city TYPE string, END OF ty_target, ty_targets TYPE TABLE OF ty_target WITH EMPTY KEY.
DATA: lt_source TYPE TABLE OF ty_source.
lt_source = VALUE #( ( kunnr = '1000' name1 = 'Miller GmbH' ort01 = 'Berlin' ) ( kunnr = '2000' name1 = 'Schmidt AG' ort01 = 'Munich' )).
" Transformation with CORRESPONDINGDATA(lt_target) = VALUE ty_targets( FOR ls_src IN lt_source ( CORRESPONDING #( ls_src MAPPING customer_id = kunnr customer_name = name1 city = ort01 ) )).FOR Variants Overview
| Variant | Usage |
|---|---|
FOR var IN itab | Iterate over internal table |
FOR var IN itab WHERE (...) | Filtered iteration |
FOR var IN itab INDEX INTO idx | With row index |
FOR i = 1 UNTIL i > n | Counter iteration (ascending) |
FOR i = n THEN i - 1 UNTIL i < 1 | Counter iteration (descending) |
FOR i = 1 WHILE cond | Conditional iteration |
FOR GROUPS grp OF var IN itab GROUP BY ... | Grouping |
Combinations
" FOR in VALUEDATA(lt_result) = VALUE ty_tab( FOR ... ( ... ) ).
" FOR in REDUCEDATA(lv_result) = REDUCE type( INIT ... FOR ... NEXT ... ).
" FOR in NEWDATA(lr_result) = NEW ty_tab( FOR ... ( ... ) ).
" Nested FORDATA(lt_matrix) = VALUE ty_tab( FOR i = 1 UNTIL i > 3 FOR j = 1 UNTIL j > 3 ( row = i col = j )).Important Notes / Best Practice
FORis only usable withinVALUE,REDUCE,NEW– not standalone.- WHERE filters more efficiently than subsequent
IFin the body. - INDEX INTO provides the current row index (1-based).
- Nested
FORcreates Cartesian products – be careful with large tables! FOR GROUPSis powerful for aggregations by grouping fields.LETenables local helper variables within the FOR expression.BASEpreserves existing table entries when building.- Combine with
CORRESPONDINGfor structure transformations. FOR ... UNTIL/WHILEfor iterations without source table (number sequences, etc.).- For complex logic, a
LOOP ATmay be more readable.