Der Loop-Befehl ist der wichtigste Schleifenbefehl der ABAP-Programmiersprache. Er ist so wichtig wie der for-Befehl oder der Iterator in Java.
Was ist der LOOP-Befehl in ABAP?
Der LOOP-Befehl gehört zu den wichtigsten Sprachkonstrukten in ABAP. Er ermöglicht das sequentielle Durchlaufen einer internen Tabelle.
Eine interne Tabelle ist eine Tabellenstruktur in deinem ABAP-Programm. Diese hast du vorher manuell aufgebaut oder durch einen Datenbank-Select befüllt.
Mit dem LOOP-Befehl gehst du nun jede Zeile dieser internen Tabelle der Reihe nach durch. Dabei wird pro Schleifendurchlauf eine Zeile nach der anderen aus der Tabelle in eine Arbeitsstruktur (oder in ein Field-Symbol) kopiert. Innerhalb der Schleife kannst du dann mit den Daten dieser Zeile arbeiten.
Ein einfaches Beispiel für LOOP AT … INTO .. ENDLOOP
Hier ist ein einfaches Beispiel für den ABAP-Loop-Befehl. Die anderen Varianten machen wir im Anschluss.
DATA: lt_tab TYPE STANDARD TABLE OF sflight, ls_row TYPE sflight. " Beispiel: Füllen der Tabelle lt_tab SELECT * FROM sflight INTO TABLE lt_tab UP TO 10 ROWS. " Anschließend Schleife über die gelesenen Zeilen LOOP AT lt_tab INTO ls_row. WRITE: / 'Flugnummer:', ls_row-carrid, 'Connection:', ls_row-connid, 'Preis:', ls_row-price. ENDLOOP.
- LOOP AT lt_tab INTO ls_row: Weist der Variable
ls_row
(die gleiche Struktur wielt_tab
hat) jeweils eine Tabellenzeile zu. - ENDLOOP: Beendet die Schleife.
Das war die einfachste Variante von LOOP. Besser ist es aber, ein Feldsymbol zu verwenden.
LOOP AT lt_tabelle ASSIGNING <fs_field_symbol> … ENDLOOP
Auch in diesem Fall wird die Tabelle zeilenweise durchgegangen. Allerdings erfolgt die Zuweisung der Zeile auf ein Field Symbol. Die Daten werden also nicht kopiert. Es wird nur eine Referenz gesetzt. Die Tabellenzeile und die Daten des Feldsymbols sind ein- und dieselben. Eine Änderung der Tabellenzeile ändert auch den Inhalt des Feldsymbols und anders herum wird eine Änderung im Feldsymbol auch direkt in der Tabelle durchgeführt. Das ist dann praktisch, wenn man in der Schleife auch die Tabelle ändern will.
DATA: lt_tab TYPE STANDARD TABLE OF sflight. FIELD-SYMBOLS: <fs_row> TYPE sflight. " Beispiel: Füllen der Tabelle lt_tab SELECT * FROM sflight INTO TABLE lt_tab UP TO 10 ROWS. " Anschließend Schleife mit Field-Symbol LOOP AT lt_tab ASSIGNING <fs_row>. WRITE: / 'Flugnummer:', <fs_row>-carrid, 'Connection:', <fs_row>-connid, 'Preis:', <fs_row>-price. ENDLOOP.
Der Vorteil bei den Field-Symbols ist: du kannst hier auch direkt die Tabelle ändern.
<fs_row>-connid = '4711'.
Tabelle ändern bei LOOP AT
Auch dann, wenn man LOOP AT into ls_struktur verwendet, kann man die zugrunde liegende Tabelle ändern. Der Trick ist dies Systemvariable sy-tabix, die uns sagt, welche Zeile der Tabelle sich gerade in ls_struktur befindet. Hier ein direktes Beispiel:
LOOP AT lt_sflight INTO ls_sflight. " Modify the flight date to SY-DATUM based on the loop index lt_sflight[ sy-tabix ]-fldate = sy-datum. endloop.
Es geht aber auch etwas anders: erst ls_sflight ändern und dann ls_sflight in die Tabelle zurückschreiben:
LOOP AT lt_sflight INTO ls_sflight. " Modify the flight date to SY-DATUM ls_sflight-fldate = sy-datum. " Update the original table with the modified work area using sy-tabix MODIFY lt_sflight FROM ls_sflight INDEX sy-tabix TRANSPORTING fldate.
Modify ändert die Tabelle lt_sflight mit den Daten aus ls_sflight. Die Zeile wird über den tabix bestimmt. Man kann dann noch mit transporting die Felder angeben, die überhaupt nur übernommen werden sollen. Wenn alle Felder übernommen werden sollen, kann dert transporting-Zusatz auch entfallen.
Wie du siehst: es sind immer Klimmzüge, wenn du die Tabelle bei loop at … into ändern willst. Deutlich einfacher ist es, den Loop in ein Field Symbol zu füttern und direkt auf die Tabelle durchzugreifen.
Inline-Deklarationen bei LOOP AT
Seit einiger Zeit bietet ABAP es an, Variablen inline bei der ersten Verwendung zu deklarieren und dabei auch die Datentypen aus dem Kontext abzuleiten. Das ist auch hier möglich. Das sieht dann so aus:
LOOP AT lt_table INTO DATA(ls_sflight). bzw. LOOP AT lt_sflight ASSIGNING FIELD-SYMBOL(<fs_sflight>).
Die DATA-Anweisung bzw. die FIELD-SYMBOL-Deklaration steht also direkt beim LOOP-Befehl. Es ist in diesem Fall keine Typangabe nötig. ABAP erkennt den Typ anhand des Zeilentyps der internen Tabelle.
Wie kann ich einen LOOP in ABAP vorzeitig verlassen?
LOOP mit EXIT: In der LOOP-Schleife gibt es die Möglichkeit, die Schleife jederzeit abzubrechen:
LOOP AT lt_sflight INTO ls_sflight. IF ls_sflight-price > 1000. EXIT. " Exit the loop if a price is greater than 1000 ENDIF. .... ENDLOOP.
Das Programm wird dann unmittelbar nach dem LOOP mit dem nächsten Befehl fortgesetzt. Die anderen Schleifendurchläufe entfallen komplett.
LOOP mit CONTINUE.
In der LOOP-Schleife gibt es auch die Möglichkeit, Zeilen zu überspringen:
LOOP AT lt_sflight INTO ls_sflight. ... " Skip records with a price less than or equal to 1000 IF ls_sflight-price <= 1000. CONTINUE. ENDIF. ... ENDLOOP.
Continue bedeutet, dass der aktuelle Schleifendurchlauf beendet wird. Es kommt der nächste Schleifendurchlauf für die nächste Tabellenzeile dran, sofern noch weitere Zeilen vorhanden sind.
Mit dem Continue-Befehl ist es also möglich, sich die Daten der Zeile zunächst einmal genauer anzusehen, sich zu beraten und dann zu entscheiden, dass die Zeile doch nicht bearbeitet werden muss.
Man kann denselben Effekt auch mit dem Check-Befehl erreichen:
CHECK ls_sflight-price > 1000.
Auch damit wird der aktuelle Schleifendurchlauf beendet. Allerdings rät der Style Guide „clean ABAP“ mittlerweile offiziell davon ab, CHECK innerhalb eines LOOPs zu verwenden.
Wie verwende ich einen Loop Counter in ABAP?
Es gibt keinen eingebauten Schleifenzähler wie in anderen Sprachen, aber man kann eine Variable hochzählen:
DATA lv_counter TYPE i VALUE 0. LOOP AT lt_tab INTO ls_tab. lv_counter = lv_counter + 1. ENDLOOP. WRITE: / 'Anzahl gelesener Einträge: ', lv_counter.
Du kannst an dieser Stelle manchmal auch sy-tabix verwenden. Das liefert aber den Index innerhalb der Tabelle. Wenn du mit where gezielt Zeilen herausgesucht hast, oder wenn du auf einer sorted table
oder gar auf einer hashed table
arbeitest, dann liefert dir sy-tabix nicht die Werte, die du erwartest. Besser ist es deshalb, von Hand zu zählen.
LOOP über die Felder einer Struktur
Gibt es in ABAP ein „LOOP over structure“? Das hängt ein wenig davon ab, was man damit meint.
Oft wird „loop over structure“ einfach als ungenaue Formulierung benutzt, wenn man eigentlich über eine interne Tabelle voller Datensätze (Strukturen) iteriert. Dann genügt ein normales LOOP AT <itab>
; aber um wirklich die Felder einer einzelnen Struktur durchzugehen, brauchst du dynamische Techniken. Wir müssen uns die Felder der Struktur erst einmal zugänglich machen.
Dynamisches Iterieren über alle Felder einer Struktur
Nehmen wir als Beispiel eine Struktur, die verschiedene Felder enthält:
TYPES: BEGIN OF ty_person, name TYPE string, city TYPE string, birth_year TYPE i, END OF ty_person. DATA: ls_person TYPE ty_person. ls_person-name = 'Donald'. ls_person-city = 'Hamburg'. ls_person-birth_year = 1980.
Nun wollen wir alle Felder in ls_person
durchgehen, ohne den Quellcode explizit ändern zu müssen, falls wir später mehr Felder hinzufügen. Dazu nutzen wir DESCRIBE FIELD
und ASSIGN COMPONENT
.
Schritt 1: Anzahl der Komponenten ermitteln
Wir benötigen die Gesamtzahl an Feldern (Komponenten) in ls_person
. Diese ermitteln wir mit DESCRIBE FIELD ls_person ... COMPONENTS lv_components
.
Das geht so:
DATA lv_components TYPE i. DATA lv_type TYPE c LENGTH 1. DESCRIBE FIELD ls_person TYPE lv_type COMPONENTS lv_components. write : / 'Typcode:', lv_type. write : / 'Anzahl Komponenten:', lv_components.
Der Typcode ist hier „V“ für „deep structure. Wir brauchen diesen eigentlich nicht, denn wir wussten ja, dass wir es mit einer Struktur zu tun haben. Aber wir kommen anders nicht an die Komponentenzahl heran.
lv_components
beinhaltet jetzt die Anzahl der Komponenten der Struktur.
Schritt 2: Alle Feld-Komponenten durchgehen
Wir verwenden eine DO-Schleife von 1 bis lv_components
. In jedem Schleifendurchlauf versuchen wir, das jeweilige Feld dynamisch zuzuweisen:
DATA: lv_index TYPE i, lv_text TYPE string. FIELD-SYMBOLS: <fs_component> TYPE any. DO lv_components TIMES. lv_index = sy-index. " sy-index läuft von 1 bis lv_components " Dynamische Zuweisung: Komponente lv_index der Struktur ls_person ASSIGN COMPONENT lv_index OF STRUCTURE ls_person TO <fs_component>. IF sy-subrc = 0. " <fs_component> zeigt jetzt auf das entsprechende Feld " Wir können uns zum Beispiel den Inhalt als Text holen: lv_text = <fs_component>. WRITE: / 'Feld', lv_index, 'Inhalt:', lv_text. ELSE. " Falls es ein Problem mit der Feldzuweisung gibt WRITE: / 'Komponente', lv_index, 'konnte nicht zugewiesen werden.'. ENDIF. ENDDO.
Die Ausgabe lautet jetzt
Typcode: v
Anzahl Komponenten: 3
Feld 1 Inhalt: Donald
Feld 2 Inhalt: Hamburg
Feld 3 Inhalt: 1980
Die Schleife listet nacheinander die Inhalte der Felder name
, city
und birth_year
auf. Wenn du weitere Felder zur Struktur hinzufügst, dann greift die Schleife diese beim nächsten Programmstart ebenfalls auf – ohne dass du etwas am LOOP selbst anpassen musst. Deshalb ist es wichtig, die Anzahl der Komponenten dynamisch zu ermitteln.
Mehr ABAP-Tips findest du hier.