Instruction ABAP LOOP AT : Parcourir et traiter des tables internes

Catégorie
ABAP-Statements
Publié
Auteur
Johannes

L’instruction LOOP AT est l’une des structures de contrôle les plus importantes en ABAP pour le traitement des tables internes. Elle permet de parcourir toutes ou des lignes sélectionnées d’une table interne de manière séquentielle et d’accéder à chaque ligne individuelle pour la lire, la modifier ou la supprimer.

Syntaxe

La syntaxe de base de l’instruction LOOP AT offre différentes variantes pour accéder aux lignes de la table :

1. LOOP avec zone de travail (INTO)

LOOP AT <interne_tabelle> INTO <arbeitsbereich>
[WHERE <bedingung>]
[FROM <index1>] [TO <index2>].
" Anweisungsblock
" <arbeitsbereich> enthält eine Kopie der aktuellen Zeile
ENDLOOP.

2. LOOP avec symbole de champ (ASSIGNING)

LOOP AT <interne_tabelle> ASSIGNING <feldsymbol>
[WHERE <bedingung>]
[FROM <index1>] [TO <index2>].
" Anweisungsblock
" <feldsymbol> zeigt direkt auf die aktuelle Zeile (kein Kopieren)
ENDLOOP.

3. LOOP avec référence de données (REFERENCE INTO)

LOOP AT <interne_tabelle> REFERENCE INTO <datenreferenz>
[WHERE <bedingung>]
[FROM <index1>] [TO <index2>].
" Anweisungsblock
" <datenreferenz> enthält einen Zeiger auf die aktuelle Zeile
ENDLOOP.

4. LOOP sans accès aux lignes (seulement comptage)

LOOP AT <interne_tabelle> TRANSPORTING NO FIELDS
[WHERE <bedingung>].
" Anweisungsblock (z.B. nur sy-tabix nutzen)
ENDLOOP.

Composants

  • <interne_tabelle> : La table dont les lignes doivent être parcourues.
  • INTO <arbeitsbereich> : Le contenu de la ligne actuelle est copié dans la zone de travail. Les modifications de la zone de travail n’affectent pas automatiquement la table.
  • ASSIGNING <feldsymbol> : Le symbole de champ pointe directement sur la ligne actuelle dans la table. Les modifications du symbole de champ modifient immédiatement la ligne de la table.
  • REFERENCE INTO <datenreferenz> : Une référence de données qui pointe sur la ligne actuelle. Accès via déréférencement (->*).
  • WHERE <bedingung> : Filtre les lignes à parcourir. Seules les lignes qui remplissent la condition sont traitées.
  • FROM <index1> : Démarre la boucle à partir de la position d’index spécifiée (uniquement pour les tables d’index).
  • TO <index2> : Termine la boucle à la position d’index spécifiée (uniquement pour les tables d’index).
  • TRANSPORTING NO FIELDS : Aucun contenu de champ n’est transporté. Utile pour compter ou lorsque seul sy-tabix est nécessaire.

Champs système pendant la boucle

Dans un LOOP AT, des champs système importants sont définis :

  • sy-tabix : Contient l’index de ligne actuel de la ligne en cours de traitement (pour les tables standard et triées). Pour les tables de hachage, sy-tabix n’est pas défini (valeur 0).
  • sy-subrc : Après le ENDLOOP, sy-subrc = 0 si au moins une ligne a été traitée. sy-subrc = 4 si aucune ligne ne remplissait les conditions (table vide ou WHERE sans résultat).

Fonctionnement

  1. L’instruction LOOP AT commence avec la première ligne (ou la première ligne correspondante avec WHERE/FROM).
  2. À chaque itération, la ligne actuelle est fournie via le mécanisme d’accès choisi (INTO, ASSIGNING, REFERENCE INTO).
  3. Le bloc d’instructions entre LOOP AT et ENDLOOP est exécuté une fois pour chaque ligne correspondante.
  4. Après la dernière ligne (ou lorsqu’aucune ligne ne correspond plus), la boucle se termine et le programme continue après ENDLOOP.

Variantes et ajouts

Condition WHERE

Avec WHERE, les lignes peuvent être filtrées pour que seules certaines lignes soient parcourues :

LOOP AT lt_orders INTO ls_order WHERE status = 'OPEN'.
" Nur offene Bestellungen verarbeiten
ENDLOOP.

La condition WHERE supporte :

  • Opérateurs de comparaison : =, <>, <, >, <=, >=
  • Liaisons logiques : AND, OR, NOT
  • Tests de plage : BETWEEN, IN (pour Ranges)
  • Pattern-Matching : CP, NP (pour chaînes de caractères)

FROM et TO (basé sur l’index)

Pour les tables standard et triées, la plage peut être restreinte :

" Nur Zeilen 5 bis 10 verarbeiten
LOOP AT lt_data INTO ls_data FROM 5 TO 10.
" ...
ENDLOOP.
" Ab Zeile 100 bis zum Ende
LOOP AT lt_data INTO ls_data FROM 100.
" ...
ENDLOOP.

GROUP BY (Regroupement)

À partir d’ABAP 7.40, les lignes peuvent être regroupées pendant la boucle :

LOOP AT lt_orders INTO ls_order
GROUP BY ( customer = ls_order-customer_id
size = GROUP SIZE )
INTO DATA(group).
" Gruppenverarbeitung
LOOP AT GROUP group INTO DATA(member).
" Einzelne Mitglieder der Gruppe
ENDLOOP.
ENDLOOP.

INTO vs. ASSIGNING vs. REFERENCE INTO

Le choix du mécanisme d’accès influence la performance et la fonctionnalité :

VarianteCopie ?ModificationsPerformanceCas d’usage
INTOOuiNécessite MODIFYPlus lentLecture seule, pas de modifications
ASSIGNINGNonDirectPlus rapideLecture et/ou modification
REFERENCE INTONonVia ->*Plus rapideLorsqu’une référence est nécessaire

Recommandation

  • Lecture seule sans modification : ASSIGNING (plus performant que INTO)
  • Lecture et modification : ASSIGNING (les modifications sont immédiates)
  • Transmettre une référence : REFERENCE INTO
  • Copie explicitement souhaitée : INTO

Exemples

1. LOOP simple avec 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.
" Tabelle füllen (Beispieldaten)
lt_materials = VALUE #(
( matnr = 'MAT001' maktx = 'Schraube M6' menge = 100 )
( matnr = 'MAT002' maktx = 'Mutter M6' menge = 200 )
( matnr = 'MAT003' maktx = 'Scheibe M6' menge = 150 )
).
" Alle Materialien ausgeben
LOOP AT lt_materials INTO ls_material.
WRITE: / sy-tabix, ':', ls_material-matnr, ls_material-maktx.
ENDLOOP.

2. LOOP avec ASSIGNING et modification de valeur

FIELD-SYMBOLS: <fs_material> TYPE ty_material.
" Alle Mengen um 10% erhöhen
LOOP AT lt_materials ASSIGNING <fs_material>.
<fs_material>-menge = <fs_material>-menge * '1.1'.
ENDLOOP.
" Änderungen sind sofort in lt_materials wirksam!

3. LOOP avec condition WHERE

DATA: lv_total TYPE i VALUE 0.
" Nur Materialien mit Menge > 100 summieren
LOOP AT lt_materials INTO ls_material WHERE menge > 100.
lv_total = lv_total + ls_material-menge.
ENDLOOP.
WRITE: / 'Gesamtmenge (>100):', lv_total.
IF sy-subrc <> 0.
WRITE: / 'Keine Materialien mit Menge > 100 gefunden.'.
ENDIF.

4. LOOP avec REFERENCE INTO

DATA: lr_material TYPE REF TO ty_material.
LOOP AT lt_materials REFERENCE INTO lr_material.
" Zugriff über Dereferenzierung
lr_material->menge = lr_material->menge + 50.
ENDLOOP.

5. Supprimer des lignes dans LOOP

" Zeilen mit Menge = 0 entfernen
LOOP AT lt_materials ASSIGNING <fs_material>.
IF <fs_material>-menge = 0.
DELETE lt_materials.
ENDIF.
ENDLOOP.

Remarque : La suppression de lignes dans un LOOP est autorisée. La boucle continue correctement avec la ligne suivante. Voir aussi DELETE pour d’autres variantes.

6. LOOP avec FROM/TO pour 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.
" Zeilen 11-20 verarbeiten (Seite 2)
WRITE: / ls_material-matnr.
ENDLOOP.

7. TRANSPORTING NO FIELDS pour compter

DATA: lv_count TYPE i VALUE 0.
LOOP AT lt_materials TRANSPORTING NO FIELDS WHERE menge > 100.
lv_count = lv_count + 1.
ENDLOOP.
WRITE: / 'Anzahl Materialien mit Menge > 100:', lv_count.

Astuce : Pour le comptage pur, la fonction REDUCE ou lines() avec FILTER est souvent plus élégante :

DATA(lv_count) = REDUCE i( INIT count = 0
FOR wa IN lt_materials WHERE ( menge > 100 )
NEXT count = count + 1 ).

Différenciation avec d’autres instructions

LOOP vs. READ TABLE

  • LOOP AT : Parcourt plusieurs/toutes les lignes de manière séquentielle.
  • READ TABLE : Lit une seule ligne spécifique (par clé ou index).

Pour l’accès à une seule ligne, READ TABLE est plus performant :

" Einzelne Zeile per Schlüssel
READ TABLE lt_materials INTO ls_material WITH KEY matnr = 'MAT001'.
" Einzelne Zeile per Index
READ TABLE lt_materials INTO ls_material INDEX 1.

LOOP vs. Expression FOR

À partir d’ABAP 7.40, il existe l’expression FOR pour les itérations en ligne :

" Neue Tabelle mit gefilterten Daten erstellen
DATA(lt_filtered) = VALUE ty_materials(
FOR wa IN lt_materials WHERE ( menge > 100 )
( wa )
).

LOOP AT reste le choix préféré pour une logique de traitement complexe avec plusieurs instructions.

Contrôle de boucle

Dans un LOOP AT, les instructions suivantes peuvent contrôler la boucle :

  • CONTINUE : Passe à l’itération suivante (saute le reste du passage actuel).
  • EXIT : Termine immédiatement la boucle et continue après ENDLOOP.
  • CHECK : Termine l’itération actuelle si la condition est fausse (comme IF NOT ... CONTINUE).
LOOP AT lt_materials ASSIGNING <fs_material>.
" Materialien ohne Text überspringen
CHECK <fs_material>-maktx IS NOT INITIAL.
" Bei speziellem Material abbrechen
IF <fs_material>-matnr = 'STOP'.
EXIT.
ENDIF.
" Verarbeitung...
ENDLOOP.

Conseils de performance

  1. ASSIGNING au lieu de INTO : Évite la copie de données et est nettement plus rapide pour les grandes structures.

  2. Utiliser la condition WHERE : Filtre les lignes à traiter et réduit le nombre d’itérations.

  3. Clé secondaire : Pour les requêtes WHERE fréquentes sur certains champs, une clé secondaire peut améliorer les performances. Voir aussi SORT pour la préparation de recherches binaires.

  4. PARALLEL CURSOR : Lors du traitement de deux tables triées avec relation entre elles, la technique de curseur parallèle peut améliorer drastiquement les performances :

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.
" Item verarbeiten...
ENDLOOP.
ENDLOOP.
  1. Éviter les LOOPs imbriqués sans index : Deux boucles imbriquées sur de grandes tables sans optimisation conduisent à une complexité O(n²).

Remarques importantes / Bonnes pratiques

  • LOOP AT est fondamental pour travailler avec les tables internes en ABAP. Chargez d’abord les données avec SELECT depuis la base de données.
  • Préférez ASSIGNING pour de meilleures performances et un accès direct en écriture.
  • Utilisez les conditions WHERE pour ne traiter que les lignes pertinentes.
  • N’oubliez jamais le ENDLOOP final.
  • Vérifiez sy-subrc après la boucle si vous devez savoir si des lignes ont été traitées.
  • Pour les tables de hachage, sy-tabix n’est pas disponible – utilisez plutôt vos propres compteurs si nécessaire.
  • Pour le développement ABAP moderne (à partir de 7.40), vérifiez si les expressions FOR ou REDUCE sont plus appropriées pour votre cas d’usage.