ABAP FOR: Inline-Iteration in Ausdrücken

kategorie
ABAP-Statements
Veröffentlicht
autor
Johannes

Der FOR-Ausdruck ermöglicht Inline-Iteration innerhalb von Konstruktorausdrücken wie VALUE, REDUCE und NEW. Er ersetzt viele LOOP AT ... APPEND-Konstrukte durch kompakte, funktionale Syntax.

Syntax

1. FOR … IN (Tabelleniteration)

FOR <variable> IN <tabelle> [ INDEX INTO <index> ] [ WHERE ( <bedingung> ) ]

2. FOR … UNTIL/WHILE (Bedingte Iteration)

FOR <variable> = <startwert> [ THEN <ausdruck> ] UNTIL <bedingung>
FOR <variable> = <startwert> [ THEN <ausdruck> ] WHILE <bedingung>

3. FOR GROUPS (Gruppierung)

FOR GROUPS <gruppe> OF <variable> IN <tabelle>
GROUP BY <gruppierungsausdruck>

Grundprinzip

FOR wird innerhalb von VALUE, REDUCE oder NEW verwendet:

" Tabelle aus anderer Tabelle erstellen
DATA(lt_result) = VALUE ty_result_tab(
FOR ls_source IN lt_source
( feld1 = ls_source-feld1 feld2 = ls_source-feld2 )
).

Beispiele

1. Einfache Tabellentransformation

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 )
).
" Nur Namen extrahieren
DATA(lt_names) = VALUE ty_names(
FOR ls_person IN lt_persons
( ls_person-name )
).
" Ergebnis: Max, Anna, Peter

2. Vergleich: FOR vs. LOOP

" === KLASSISCH MIT 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 MIT FOR ===
DATA(lt_names_modern) = VALUE ty_names(
FOR ls_p IN lt_persons
( ls_p-name )
).

3. FOR mit WHERE (Filtern)

" Nur Erwachsene (age >= 18)
DATA(lt_adults) = VALUE ty_persons(
FOR ls_person IN lt_persons
WHERE ( age >= 18 )
( ls_person )
).
" Komplexere Bedingung
DATA(lt_filtered) = VALUE ty_persons(
FOR ls_person IN lt_persons
WHERE ( age >= 25 AND name <> 'Max' )
( ls_person )
).

4. Transformation mit Berechnung

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 )
).
" Bestellpositionen mit Gesamtpreis berechnen
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 – Zeilenindex mitlesen

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 )
).
" Ergebnis:
" position = 1, name = 'Max'
" position = 2, name = 'Anna'
" position = 3, name = 'Peter'

6. Verschachtelte FOR (Kartesisches Produkt)

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 #( ( `Rot` ) ( `Blau` ) ( `Grün` ) ).
lt_sizes = VALUE #( ( `S` ) ( `M` ) ( `L` ) ).
" Alle Kombinationen erstellen
DATA(lt_variants) = VALUE ty_variants(
FOR lv_color IN lt_colors
FOR lv_size IN lt_sizes
( color = lv_color
size = lv_size )
).
" Ergebnis: 9 Kombinationen (3x3)
" Rot-S, Rot-M, Rot-L, Blau-S, Blau-M, ...

7. FOR … UNTIL (Bedingte Iteration)

TYPES: ty_numbers TYPE TABLE OF i WITH EMPTY KEY.
" Zahlen 1 bis 10 generieren
DATA(lt_1_to_10) = VALUE ty_numbers(
FOR i = 1 UNTIL i > 10
( i )
).
" Mit THEN für Schrittweite
DATA(lt_even) = VALUE ty_numbers(
FOR i = 2 THEN i + 2 UNTIL i > 20
( i )
).
" Ergebnis: 2, 4, 6, 8, 10, 12, 14, 16, 18, 20

8. FOR … WHILE

" Quadratzahlen unter 100
DATA(lt_squares) = VALUE ty_numbers(
FOR n = 1 WHILE n * n < 100
( n * n )
).
" Ergebnis: 1, 4, 9, 16, 25, 36, 49, 64, 81

9. FOR GROUPS – Gruppierung

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.
" Summe pro 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
)
)
).
" Ergebnis:
" NORTH: 2500.00
" SOUTH: 3200.00
" EAST: 800.00

10. FOR GROUPS mit mehreren Gruppierungsfeldern

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.
" Gruppierung nach Jahr und Monat
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 für lokale Variablen

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

" Summe aller Beträge
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
).
" Mit WHERE filtern
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 (Datenreferenzen)

" Tabelle als Referenz erstellen
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. Bestehendes erweitern (BASE)

DATA: lt_existing TYPE ty_names.
lt_existing = VALUE #( ( `Existing1` ) ( `Existing2` ) ).
" Neue Einträge hinzufügen
DATA(lt_combined) = VALUE ty_names(
BASE lt_existing
FOR ls_person IN lt_persons
( ls_person-name )
).
" Ergebnis: Existing1, Existing2, Max, Anna, Peter

15. Komplexe Transformation mit 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 = 'Müller GmbH' ort01 = 'Berlin' )
( kunnr = '2000' name1 = 'Schmidt AG' ort01 = 'München' )
).
" Transformation mit 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-Varianten im Überblick

VarianteVerwendung
FOR var IN itabIteration über interne Tabelle
FOR var IN itab WHERE (...)Gefilterte Iteration
FOR var IN itab INDEX INTO idxMit Zeilenindex
FOR i = 1 UNTIL i > nZähler-Iteration (aufwärts)
FOR i = n THEN i - 1 UNTIL i < 1Zähler-Iteration (abwärts)
FOR i = 1 WHILE condBedingte Iteration
FOR GROUPS grp OF var IN itab GROUP BY ...Gruppierung

Kombinationen

" 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 ... ( ... ) ).
" Verschachtelte FOR
DATA(lt_matrix) = VALUE ty_tab(
FOR i = 1 UNTIL i > 3
FOR j = 1 UNTIL j > 3
( row = i col = j )
).

Wichtige Hinweise / Best Practice

  • FOR ist nur innerhalb von VALUE, REDUCE, NEW verwendbar – nicht standalone.
  • WHERE filtert effizienter als nachträgliches IF im Rumpf.
  • INDEX INTO liefert den aktuellen Zeilenindex (1-basiert).
  • Verschachtelte FOR erzeugen kartesische Produkte – Vorsicht bei großen Tabellen!
  • FOR GROUPS ist mächtig für Aggregationen nach Gruppierungsfeldern.
  • LET ermöglicht lokale Hilfsvariablen innerhalb des FOR-Ausdrucks.
  • BASE erhält bestehende Tabelleneinträge beim Aufbau.
  • Kombinieren Sie mit CORRESPONDING für Strukturtransformationen.
  • FOR ... UNTIL/WHILE für Iterationen ohne Quelltabelle (Zahlenreihen etc.).
  • Bei komplexer Logik kann ein LOOP AT lesbarer sein.