ABAP - Schleifen
Mit dem modernen ABAP wurden auch neue Schleifen und Möglichkeiten zur Einschränkung von Tabelleninhalten geschaffen. Diese neuen Befehle schauen wir uns in diesem Artikel näher an.
Inhaltsverzeichnis
Im ersten Schritt können wir dir aber schon einmal sagen, dass der LOOP noch nicht komplett obsolet geworden ist und du ihn noch weiter verwenden kannst. Mit den neuen Möglichkeiten sind an einigen Stellen nur effizientere und kürzere Funktionen geschaffen worden.
FOR
Endlich gibt es auch eine FOR-Schleife in ABAP, lange haben die Entwickler darauf gewartet. Doch taugt die Schleife zum Ablösen des klassischen LOOP? Nicht ganz, können wir dir sagen, vor allem wenn du noch etwas mehr Logik in die Schleife packen möchtest. Entsprechend kommt die Ausführung in den zwei klassichen Varianten.
Im ersten Schritt einmal die Übersicht des Datentypen, den wir für die folgenden Beispiele verwenden wollen. Dieser besteht zu einem Teil aus technischen Daten und zum anderen Teil aus Buchungskreis-Daten.
TYPES:
BEGIN OF ts_idata,
index TYPE sy-tabix,
adate TYPE d,
bukrs TYPE t001-bukrs,
butxt TYPE t001-butxt,
land1 TYPE t001-land1,
END OF ts_idata,
tt_idata TYPE STANDARD TABLE OF ts_idata WITH EMPTY KEY.
FOR-EACH Schleife
In anderen Programmiersprachen wäre diese Schleife als FOR EACH bekannt, in ABAP verwendest du dafür einfach die klassichen FOR Schleife mit IN Zusatz um über die Daten zu iterieren und diese an die Zieltabelle zu hängen. Gleichzeitig reichern wir die Daten noch mit dem Tabellenindex an und setzen das aktuelle Datum. Im folgenden Beispiel einmal für den klassichen Weg mit LOOP und die neue Variante.
" Old
DATA(lt_old) = VALUE tt_idata( ).
LOOP AT lt_bukrs INTO DATA(ls_bukrs) WHERE land1 = 'DE'.
DATA(ld_tabix) = sy-tabix.
INSERT VALUE #(
bukrs = ls_bukrs-bukrs
butxt = ls_bukrs-butxt
land1 = ls_bukrs-land1
adate = sy-datum
index = ld_tabix
) INTO TABLE lt_old.
ENDLOOP.
" New
DATA(lt_new) = VALUE tt_idata(
FOR ls_bukrs IN lt_bukrs INDEX INTO ld_index WHERE ( land1 = 'DE' ) (
bukrs = ls_bukrs-bukrs
butxt = ls_bukrs-butxt
land1 = ls_bukrs-land1
adate = sy-datum
index = ld_index
)
).
Zählschleife
Ebenfalls gibt es nun die klassche Zählschleife, wenn du einmal durchzählen willst und eine Tabelle zum Beispiel mit Testdaten initialisieren willst. Die Variable wird in der Schleife definiert und mit einem Startwert versehen. Entsprechend kann auch ein anderer Datentyp als eine String-Tabelle verwendet werden.
DATA:
lt_text TYPE string_table.
it_strings = VALUE #( FOR ld_x = 1 THEN ld_x + 2 WHILE ld_x < 50 ( |{ ld_x }| ) ).
REDUCE
Der neue Befehl kann beim Verstehen etwas komplex werden, ist aber im Grunde genommen eine Reduzierung von Tabellendaten (1-n Tabellen-Iterationen) in einen neuen Datentypen. Dieser kann eine Tabelle sein, aber auch eine Zahl, wenn zum Beispiel eine Summation erfolgte.
Im folgenden Beispiel reduzieren wir die Daten in der Quelltabelle und führen diesen in einer neuen Tabelle zusammen, einige Feldinhalte werden dabei geändert. Am Ende erzeugen wir per Inline-Deklaration unsere neue Zieltabelle.
DATA(lt_new) = REDUCE tt_idata(
INIT lt_result TYPE tt_idata
FOR ls_old_bukrs IN lt_bukrs WHERE ( land1 <> 'DE' )
NEXT lt_result = VALUE #( BASE lt_result
( bukrs = ls_old_bukrs-bukrs butxt = |+{ ls_old_bukrs-bukrs+1(3) }| land1 = ls_old_bukrs-land1 )
)
).
Hinweis: Dieser Befehl wird dir wahrscheinlich nicht all zu oft über den Weg laufen, du solltest ihn aber ungefähr verstanden haben.
FILTER
Der Filter ist ein sehr interessanter neuer Befehl, da er eine Vielzahl von Möglichkeiten zur Verfügung stellt, die Daten in einer Tabelle zu filtern und direkt eine neue Tabelle zurück zu geben. So gibt es die Möglichkeit mit einer WHERE Kondition zu arbeiten oder einfach eine andere Tabelle als Filter heran zu ziehen. Der Zieldatentyp muss nicht zwingend angegeben werden und kann sich aus den Originaldaten ableiten.
Dazu definieren wir eine Struktur, sowie den entsprechenden Tabellentypen. Zu Beachten wäre, dass die Tabelle einenprimären und sekundären Schlüssel erhält, da dieser für die Verwendung des Befehls FILTER benötigt wird.
TYPES:
BEGIN OF ts_data,
lnum TYPE i,
text TYPE string,
date TYPE d,
END OF ts_data,
tt_data TYPE SORTED TABLE OF ts_data WITH NON-UNIQUE KEY date
WITH NON-UNIQUE SORTED KEY by_text COMPONENTS text.
In dem folgenden Beispiel stellen wir für dich die klassische und neue Variante gegenüber. Wie du siehst ist der Block nun etwas kürzer und übersichtlicher geworden.
" Old
DATA(lt_result) = VALUE tt_data( ).
LOOP AT mt_data INTO DATA(ls_data) WHERE date < CONV d( '20200201' ).
INSERT ls_data INTO TABLE lt_result.
ENDLOOP.
" New
DATA(lt_result) = FILTER #( mt_data WHERE date < CONV d( '20200201' ) ).
Wenn du die Daten über einen sekundären Schlüssel filtern möchtest, dann musst du diesen expliziet angeben, damit der Befehl dies mitbekommt und den Index nutzt. In dem folgenden Beispiel wollen wir den Text Schlüssel nutzen, den wir oben definiert haben.
DATA(lt_result) = FILTER #( mt_data USING KEY by_text WHERE text = `Nails` ).
Fazit
Wie du an den Beispielen gesehen hast, geben dir die neuen Befehle Möglichkeiten kürzeren Quellcode zu schreiben, aber auch hier solltest du vorsichtig mit der Formatierung sein. Auch schlecht formatierter Quellcode kann schnell an Lesbarkeit verlieren und hierbei geht es nicht um die Lesbarkeit durch dich als Schreiber, sondern deiner Kollegen.
Quelle:
SAP Dokumentation - FOR
SAP Dokumentation - REDUCE
SAP Dokumentation - FILTER