ABAP FOR: Inline Iteration in Expressions

Category
ABAP-Statements
Published
Author
Johannes

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 table
DATA(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 names
DATA(lt_names) = VALUE ty_names(
FOR ls_person IN lt_persons
( ls_person-name )
).
" Result: Max, Anna, Peter

2. 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 condition
DATA(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 price
DATA(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 combinations
DATA(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 10
DATA(lt_1_to_10) = VALUE ty_numbers(
FOR i = 1 UNTIL i > 10
( i )
).
" With THEN for step size
DATA(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, 20

8. FOR … WHILE

" Square numbers under 100
DATA(lt_squares) = VALUE ty_numbers(
FOR n = 1 WHILE n * n < 100
( n * n )
).
" Result: 1, 4, 9, 16, 25, 36, 49, 64, 81

9. 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 region
DATA(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.00

10. 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 month
DATA(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 amounts
DATA(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 WHERE
DATA(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 reference
DATA(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 entries
DATA(lt_combined) = VALUE ty_names(
BASE lt_existing
FOR ls_person IN lt_persons
( ls_person-name )
).
" Result: Existing1, Existing2, Max, Anna, Peter

15. 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 CORRESPONDING
DATA(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

VariantUsage
FOR var IN itabIterate over internal table
FOR var IN itab WHERE (...)Filtered iteration
FOR var IN itab INDEX INTO idxWith row index
FOR i = 1 UNTIL i > nCounter iteration (ascending)
FOR i = n THEN i - 1 UNTIL i < 1Counter iteration (descending)
FOR i = 1 WHILE condConditional iteration
FOR GROUPS grp OF var IN itab GROUP BY ...Grouping

Combinations

" FOR in VALUE
DATA(lt_result) = VALUE ty_tab( FOR ... ( ... ) ).
" FOR in REDUCE
DATA(lv_result) = REDUCE type( INIT ... FOR ... NEXT ... ).
" FOR in NEW
DATA(lr_result) = NEW ty_tab( FOR ... ( ... ) ).
" Nested FOR
DATA(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

  • FOR is only usable within VALUE, REDUCE, NEW – not standalone.
  • WHERE filters more efficiently than subsequent IF in the body.
  • INDEX INTO provides the current row index (1-based).
  • Nested FOR creates Cartesian products – be careful with large tables!
  • FOR GROUPS is powerful for aggregations by grouping fields.
  • LET enables local helper variables within the FOR expression.
  • BASE preserves existing table entries when building.
  • Combine with CORRESPONDING for structure transformations.
  • FOR ... UNTIL/WHILE for iterations without source table (number sequences, etc.).
  • For complex logic, a LOOP AT may be more readable.