Zahlreiche Tabellen in SAP bestehen aus sehr vielen, fast gleich lautenden Spalten. In Customizing Tabellen findet man oft eine Situation wie in folgendem Beispiel aus dem WM Umfeld vor.
Die Tabelle T334p enthält alle Lagerplatztypen, auf denen in einem bestimmten Lager ein bestimmter Lagereinheitentyp gelagert werden kann.
In einem Programm sollen nun zu einem Datensatz alle Lagerplatztypen durchlaufen/verarbeitet werden. Hier wäre eine Schleife um die einzelnen Spalten hilfreich. Zwar gibt es im ABAP Sprachumfang keine passende Anweisung, ich möchte an dieser Stelle aber eine Lösung vorstellen, mit der solche Tabellen komfortabel verarbeitet werden können.
Die erlaubten Lagerplatztypen sind in den Spalten LPTY0 bis LPT30 enthalten.
Simple Lösung mit IF
Die auf den ersten Blick einfachste Lösung ist das Verwenden von einem großen IF Statement, in dem alle Spalten abgefragt werden. Dies könnte z.B. so aussehen
REPORT Z_COLUMN_LOOP. data: ls_t334p type t334P, my_lptyp type lvs_lptyp value 'A1'. select * from t334p into ls_t334p where lgnum = '101' and letyp = 'E60'. if ls_t334p-lpty0 = my_lptyp or ls_t334p-lpty1 = my_lptyp or ls_t334p-lpty2 = my_lptyp or ls_t334p-lpty3 = my_lptyp or ls_t334p-lpty4 = my_lptyp or ls_t334p-lpty5 = my_lptyp or ls_t334p-lpty6 = my_lptyp or ls_t334p-lpty7 = my_lptyp or ls_t334p-lpty8 = my_lptyp or ls_t334p-lpty9 = my_lptyp or ls_t334p-lpt10 = my_lptyp or ls_t334p-lpt11 = my_lptyp or ls_t334p-lpt12 = my_lptyp or ls_t334p-lpt13 = my_lptyp or ls_t334p-lpt14 = my_lptyp or ls_t334p-lpt15 = my_lptyp or ls_t334p-lpt16 = my_lptyp or ls_t334p-lpt17 = my_lptyp or ls_t334p-lpt18 = my_lptyp or ls_t334p-lpt19 = my_lptyp or ls_t334p-lpt20 = my_lptyp or ls_t334p-lpt21 = my_lptyp or ls_t334p-lpt22 = my_lptyp or ls_t334p-lpt23 = my_lptyp or ls_t334p-lpt24 = my_lptyp or ls_t334p-lpt25 = my_lptyp or ls_t334p-lpt26 = my_lptyp or ls_t334p-lpt27 = my_lptyp or ls_t334p-lpt28 = my_lptyp or ls_t334p-lpt29 = my_lptyp . write: 'Platz A1 ist in Lagernummer 101 für Lagereinheit E60 erlaubt'. endif. endselect.
Dies ist natürlich eine praktikable, aber keine zufriedenstellende Lösung. Erst recht nicht, wenn noch mehr Spalten geprüft werden müssen. Wie wäre es statt dessen, die Tabelle in eine neue Tabelle zu transponieren?
Transponierte Tabellen
In diesem Beispiel wäre es sinnvoll, die Daten in eine Tabelle von dieser Struktur zu überführen:
- LGNUM
- LETYP
- LPTYP
Diese Tabelle kann dann mit einem einzigen READ TABLE gelesen werden um zu prüfen, ob die Kombination erlaubt ist.
Hier kommt die dynamische Zuweisung von Feldsymbolen ins Spiel. Mit ihnen kann eine einzelne Komponente einer Struktur (hier eines Datensatzes) als Referenz verwendet werden.
Zunächst habe ich eine Struktur für die Zieltabelle ty_t334p_advance erstellt und die notwendigen Variablen und Feldsymbole deklariert.
REPORT z_column_loop. TYPES BEGIN OF ty_t334p_advance. TYPES: lgnum TYPE lgnum, letyp TYPE lvs_letyp, lptyp TYPE lvs_lptyp. TYPES END OF ty_t334p_advance. DATA: lt_t334p type STANDARD TABLE OF t334p, my_lptyp TYPE lvs_lptyp VALUE 'A1', lt_t334p_advance TYPE STANDARD TABLE OF ty_t334p_advance, lv_fieldname(20) TYPE c, lv_field_counter TYPE i VALUE 0, lv_field_counter_char(2) TYPE c. FIELD-SYMBOLS:TYPE ty_t334p_advance, type t334p, TYPE lvs_lptyp.
Nun erfolgt wie eben der Select auf die Customizing Tabelle
SELECT * FROM t334p INTO table lt_t334p WHERE lgnum = '101' AND letyp = 'E60'.
Da es insgesamt 30 Spalten sind (LPTY0 - LPT29) die verarbeitet werden sollen, gibt es eine DO Schleife, die bis 30 zählt. Bei jedem Durchgang wird eine Zählvariable um eins erhöht und mit ihr der Feldname für die dynamische Zuweisung erstellt
lv_field_counter = 0. loop at lt_t334p ASSIGNINGDO 30 TIMES. lv_field_counter_char = lv_field_counter. IF strlen( lv_field_counter_char ) = 1. CONCATENATE 'LPTY' lv_field_counter_char INTO lv_fieldname. ELSE. CONCATENATE 'LPT' lv_field_counter_char INTO lv_fieldname. ENDIF.
Nun erfolgt die dynamische Zuweisung der Strukturkomponente. Ist diese geglückt, wird eine neue Zeile in der Zielstruktur erstellt. Falls es nicht klappt oder die Spalte leer ist, wird die DO Schleife verlassen.
ASSIGN COMPONENT lv_fieldname OF STRUCTURETO . IF IS ASSIGNED AND IS NOT INITIAL. APPEND INITIAL LINE TO lt_t334p_advance ASSIGNING . -lgnum = -lgnum. -letyp = -letyp. -lptyp = . ELSE. EXIT. ENDIF. lv_field_counter = lv_field_counter + 1. ENDDO. endloop.
Nach dieser Vorarbeit kann leicht geprüft werden, ob ein bestimmter Wert bei dem vorgegebenen Schlüssel erlaubt ist. Beispielsweise ob im Lager mit der Nummer 101 die Lagereinheit vom Typ E60 auf dem Platztyp A1 abgestellt werden darf.
READ TABLE lt_t334p_advance ASSIGNINGWITH KEY lgnum = '101' letyp = 'E60' lptyp = my_lptyp. IF sy-subrc = 0. WRITE: 'Platz A1 ist in Lagernummer 101 für Lagereinheit E60 erlaubt'. ENDIF.
Quellcode
Zum Abschluss nochmal der gesamte Quellcode
REPORT z_column_loop. TYPES BEGIN OF ty_t334p_advance. TYPES: lgnum TYPE lgnum, letyp TYPE lvs_letyp, lptyp TYPE lvs_lptyp. TYPES END OF ty_t334p_advance. DATA: lt_t334p type STANDARD TABLE OF t334p, my_lptyp TYPE lvs_lptyp VALUE 'A1', lt_t334p_advance TYPE STANDARD TABLE OF ty_t334p_advance, lv_fieldname(20) TYPE c, lv_field_counter TYPE i VALUE 0, lv_field_counter_char(2) TYPE c. FIELD-SYMBOLS:TYPE ty_t334p_advance, type t334p, TYPE lvs_lptyp. SELECT * FROM t334p INTO table lt_t334p WHERE lgnum = '101' AND letyp = 'E60'. lv_field_counter = 0. loop at lt_t334p ASSIGNING . DO 30 TIMES. lv_field_counter_char = lv_field_counter. IF strlen( lv_field_counter_char ) = 1. CONCATENATE 'LPTY' lv_field_counter_char INTO lv_fieldname. ELSE. CONCATENATE 'LPT' lv_field_counter_char INTO lv_fieldname. ENDIF. ASSIGN COMPONENT lv_fieldname OF STRUCTURE TO . IF IS ASSIGNED AND IS NOT INITIAL. APPEND INITIAL LINE TO lt_t334p_advance ASSIGNING . -lgnum = -lgnum. -letyp = -letyp. -lptyp = . ELSE. EXIT. ENDIF. lv_field_counter = lv_field_counter + 1. ENDDO. endloop. UNASSIGN . * Verwendung READ TABLE lt_t334p_advance ASSIGNING WITH KEY lgnum = '101' letyp = 'E60' lptyp = my_lptyp. IF sy-subrc = 0. WRITE: 'Platz A1 ist in Lagernummer 101 für Lagereinheit E60 erlaubt'. ENDIF.