ABAP Loop um Spalten einer Tabelle, Tabelle transponieren

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.

Beispiel des Inhaltes der Tabelle T334P
Beispiel des Inhaltes der Tabelle T334P

Die erlaubten Lagerplatztypen sind in den Spalten LPTY0 bis LPT30 enthalten.

Aufbau der Tabelle T334P
Aufbau der Tabelle T334P

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 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. 

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 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. 

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 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. 

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.