L’expression FOR permet l’iteration inline dans les expressions constructeur comme VALUE, REDUCE et NEW. Elle remplace de nombreuses constructions LOOP AT ... APPEND par une syntaxe compacte et fonctionnelle.
Syntaxe
1. FOR … IN (Iteration sur table)
FOR <variable> IN <table> [ INDEX INTO <index> ] [ WHERE ( <condition> ) ]2. FOR … UNTIL/WHILE (Iteration conditionnelle)
FOR <variable> = <valeur_initiale> [ THEN <expression> ] UNTIL <condition>FOR <variable> = <valeur_initiale> [ THEN <expression> ] WHILE <condition>3. FOR GROUPS (Regroupement)
FOR GROUPS <groupe> OF <variable> IN <table> GROUP BY <expression_regroupement>Principe de base
FOR est utilise dans VALUE, REDUCE ou NEW :
" Creer une table a partir d'une autre tableDATA(lt_result) = VALUE ty_result_tab( FOR ls_source IN lt_source ( champ1 = ls_source-champ1 champ2 = ls_source-champ2 )).Exemples
1. Transformation de table simple
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 )).
" Extraire uniquement les nomsDATA(lt_names) = VALUE ty_names( FOR ls_person IN lt_persons ( ls_person-name )).
" Resultat : Max, Anna, Peter2. Comparaison : FOR vs. LOOP
" === CLASSIQUE AVEC 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.
" === MODERNE AVEC FOR ===DATA(lt_names_modern) = VALUE ty_names( FOR ls_p IN lt_persons ( ls_p-name )).3. FOR avec WHERE (Filtrage)
" Uniquement les adultes (age >= 18)DATA(lt_adults) = VALUE ty_persons( FOR ls_person IN lt_persons WHERE ( age >= 18 ) ( ls_person )).
" Condition plus complexeDATA(lt_filtered) = VALUE ty_persons( FOR ls_person IN lt_persons WHERE ( age >= 25 AND name <> 'Max' ) ( ls_person )).4. Transformation avec calcul
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 )).
" Calculer les lignes de commande avec prix totalDATA(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 - Lire l’index de ligne
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 )).
" Resultat :" position = 1, name = 'Max"" position = 2, name = 'Anna"" position = 3, name = 'Peter"6. FOR imbrique (Produit cartesien)
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 #( ( `Rouge` ) ( `Bleu` ) ( `Vert` ) ).lt_sizes = VALUE #( ( `S` ) ( `M` ) ( `L` ) ).
" Creer toutes les combinaisonsDATA(lt_variants) = VALUE ty_variants( FOR lv_color IN lt_colors FOR lv_size IN lt_sizes ( color = lv_color size = lv_size )).
" Resultat : 9 combinaisons (3x3)" Rouge-S, Rouge-M, Rouge-L, Bleu-S, Bleu-M, ...7. FOR … UNTIL (Iteration conditionnelle)
TYPES: ty_numbers TYPE TABLE OF i WITH EMPTY KEY.
" Generer les nombres 1 a 10DATA(lt_1_to_10) = VALUE ty_numbers( FOR i = 1 UNTIL i > 10 ( i )).
" Avec THEN pour le pasDATA(lt_even) = VALUE ty_numbers( FOR i = 2 THEN i + 2 UNTIL i > 20 ( i ))." Resultat : 2, 4, 6, 8, 10, 12, 14, 16, 18, 208. FOR … WHILE
" Carres inferieurs a 100DATA(lt_squares) = VALUE ty_numbers( FOR n = 1 WHILE n * n < 100 ( n * n ))." Resultat : 1, 4, 9, 16, 25, 36, 49, 64, 819. FOR GROUPS - Regroupement
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.
" Somme par 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 ) )).
" Resultat :" NORTH: 2500.00" SOUTH: 3200.00" EAST: 800.0010. FOR GROUPS avec plusieurs champs de regroupement
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.
" Regroupement par annee et moisDATA(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 pour les variables locales
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 dans REDUCE
" Somme de tous les montantsDATA(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).
" Avec filtrage 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 dans NEW (References de donnees)
" Creer une table comme 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. Etendre l’existant (BASE)
DATA: lt_existing TYPE ty_names.
lt_existing = VALUE #( ( `Existing1` ) ( `Existing2` ) ).
" Ajouter de nouvelles entreesDATA(lt_combined) = VALUE ty_names( BASE lt_existing FOR ls_person IN lt_persons ( ls_person-name )).
" Resultat : Existing1, Existing2, Max, Anna, Peter15. Transformation complexe avec 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 = 'Mueller GmbH' ort01 = 'Berlin' ) ( kunnr = '2000' name1 = 'Schmidt AG' ort01 = 'Munich' )).
" Transformation avec CORRESPONDINGDATA(lt_target) = VALUE ty_targets( FOR ls_src IN lt_source ( CORRESPONDING #( ls_src MAPPING customer_id = kunnr customer_name = name1 city = ort01 ) )).Apercu des variantes FOR
| Variante | Utilisation |
|---|---|
FOR var IN itab | Iteration sur table interne |
FOR var IN itab WHERE (...) | Iteration filtree |
FOR var IN itab INDEX INTO idx | Avec index de ligne |
FOR i = 1 UNTIL i > n | Iteration compteur (croissant) |
FOR i = n THEN i - 1 UNTIL i < 1 | Iteration compteur (decroissant) |
FOR i = 1 WHILE cond | Iteration conditionnelle |
FOR GROUPS grp OF var IN itab GROUP BY ... | Regroupement |
Combinaisons
" FOR dans VALUEDATA(lt_result) = VALUE ty_tab( FOR ... ( ... ) ).
" FOR dans REDUCEDATA(lv_result) = REDUCE type( INIT ... FOR ... NEXT ... ).
" FOR dans NEWDATA(lr_result) = NEW ty_tab( FOR ... ( ... ) ).
" FOR imbriqueDATA(lt_matrix) = VALUE ty_tab( FOR i = 1 UNTIL i > 3 FOR j = 1 UNTIL j > 3 ( row = i col = j )).Conseils importants / Bonnes pratiques
FORn’est utilisable que dansVALUE,REDUCE,NEW- pas de maniere autonome.- WHERE filtre plus efficacement qu’un
IFdans le corps. - INDEX INTO fournit l’index de ligne actuel (base 1).
- Les
FORimbriques creent des produits cartesiens - attention avec les grandes tables ! FOR GROUPSest puissant pour les agregations par champs de regroupement.LETpermet des variables auxiliaires locales dans l’expression FOR.BASEpreserve les entrees de table existantes lors de la construction.- Combinez avec
CORRESPONDINGpour les transformations de structure. FOR ... UNTIL/WHILEpour les iterations sans table source (series de nombres, etc.).- Pour une logique complexe, un
LOOP ATpeut etre plus lisible.