This is a test message to test the length of the message box.
Login
|
ABAP ASSIGN
Erstellt von Software-Heroes

ABAP - Assign

493

In diesem Artikel schauen wir uns verschiedene Varianten von ASSIGN an und wie du sie in ABAP im Alltag nutzen kannst, um deine Entwicklung effektiver zu machen.

Werbung


In diesem Artikel gehen wir auf die Arbeit mit Feldsymbolen ein und wie du sie im Alltag nutzen kannst, dabei schauen wir uns verschiedene Beispiele aus der Verarbeitung an.

 

Einleitung

Das Statement ASSIGN gibt es schon sehr lange in der ABAP Entwicklung und gehört zum Standard Werkzeugkasten eines ABAP Entwicklers. Hierbei arbeiten wir in der Regel mit einem Feldsymbol, dass eine Referenz auf eine echte Variable darstellt. Feldsymbole und Referenzen sind beides Zeiger, die keine echten Werte enthalten, sondern auf eine Speicheradresse mit einem echten Wert zeigen.

 

Vorbereitung

Für die folgenden Beispiele nutzen wir zwei Strukturen mit den jeweiligen Typen in Tabellenform. Eine einfache Struktur enthält die Felder A bis E und wir legen noch ein Mapping an, dass wir für später benötigen, wenn wir die Struktur dynamisch verarbeiten.

TYPES: BEGIN OF simple_mapping,
         field TYPE string,
         value TYPE string,
       END OF simple_mapping.
TYPES simple_mappings TYPE STANDARD TABLE OF simple_mapping WITH EMPTY KEY.

TYPES: BEGIN OF simple_structure,
         a TYPE string,
         b TYPE string,
         c TYPE string,
         d TYPE string,
         e TYPE string,
       END OF simple_structure.
TYPES simple_table TYPE STANDARD TABLE OF simple_structure WITH EMPTY KEY.

 

Verarbeitung

Auch für Feldsymbole gibt es eine Inline Deklaration, wie du sie zum Beispiel bei einem LOOP oder einem ASSIGN verwenden kannst. In diesem Beispiel verwenden wir ein Feldsymbol, anstatt eine normale Struktur. Der Vorteil dieser Version ist auch die Performance, da wir hier nicht die Daten aus der Tabelle in die Struktur kopieren müssen, es wird lediglich der Zeiger geändert.

LOOP AT examples ASSIGNING FIELD-SYMBOL(<line>).
  out->write( <line> ).
ENDLOOP.

 

In diesem Szenario musst du allerdings vorsichtig sein, da du nun einen Zeiger hast. Über diesen kannst du direkt die Daten in der Tabelle anpassen und verändern. In diesem Beispiel setzen wir für die Spalte C einen neuen Wert und überschreiben den Alten.

LOOP AT examples ASSIGNING FIELD-SYMBOL(<line>).
  <line>-c = `New Value`.
ENDLOOP.

 

Grundsätzlich kannst du damit ganz einfach eine Menge von Daten anpassen oder weitere Informationen in der Tabelle anreichern, ohne die Daten in die Tabelle zurückschreiben zu müssen.

 

Komponente

Nehmen wir zum Beispiel einmal nur eine Struktur unserer Tabelle. Möchtest du eine Struktur dynamisch verarbeiten, stehen dir verschiedene Methoden zur Verfügung. So kannst du zum Beispiel per RTTI die Struktur analysieren, um so die verschiedenen Felder zu verarbeiten. Im folgenden Beispiel verwenden wir ein ASSIGN COMPONENT, damit können wir ein einzelnes Feld einem Feldsymbol zuweisen.

DO.
  ASSIGN COMPONENT sy-index OF STRUCTURE example TO FIELD-SYMBOL(<field>).
  IF sy-subrc <> 0.
    EXIT.
  ENDIF.

  result &&= <field>.
ENDDO.

 

Hier gibt es aktuell zwei Regeln bei der Zuweisung:

  • Numerisch - Ist der Wert hinter COMPONENT numerisch, dann wir das x-te Feld der Struktur dem Feldsymbol zugewiesen.
  • Zeichen - Besteht der Wert aus Zeichen, dann wird nach einem gleichnamigen Feld in der Struktur gesucht und im Anschluss dieses dem Feldsymbol zugeordnet.

 

In dem Beispiel oben verarbeiten wir also die Felder vom 1ten bis zum letzten Feld. Versuchen wir nun ein Feld zuzuweisen, welches es nicht mehr gibt, dann wird der SY-SUBRC gesetzt, in diesem Fall verlassen wir die Schleife und sind mit der Verarbeitung durch.

 

Mapping

Im nächsten Beispiel arbeiten wir mit einem Mapping und wollen einmal auf die Gefahren der Methode hinweisen. Dabei enthält das Mapping ein Feld, welches es aktuell nicht in der Struktur gibt.

METHOD get_mappings.
  RETURN VALUE #( ( field = `a` value = `101` )
                  ( field = `b` value = `102` )
                  ( field = `f` value = `103` )
                  ( field = `d` value = `104` )
                  ( field = `e` value = `105` ) ).
ENDMETHOD.

 

Fehlerfall

Im folgenden Beispiel erzeugen wir einen Fehler in der Verarbeitung, der unbemerkt bleiben wird. Wir erhalten aus der Methode das Mapping und verarbeiten dieses gegen unsere Struktur.

LOOP AT get_mappings( ) INTO mapping.
  ASSIGN COMPONENT mapping-field OF STRUCTURE example TO <field>.
  <field> = mapping-value.
ENDLOOP.

 

An der dritten Stelle des Mappings kann das Feld nicht mehr gemappt werden. Grundsätzlich wird nun der SUBRC gesetzt. Allerdings bleibt das Feldsymbol auf dem zweiten Feld stehen. Wir überschreiben damit das zweite Feld mit einem falschen Wert und haben unbemerkt einen Fehler erzeugt.

 

Lösung

Damit wir solche Fehler nicht mehr machen, sollten wir im Fehlerfall reagieren. In der klassischen Entwicklung würden wir nun den SUBRC prüfen, ob die Zuweisung funktioniert hat. In solch einem Fall können wir die aktuelle Zeile überspringen und die Verarbeitung auf der Nächsten fortsetzen.

LOOP AT get_mappings( ) INTO mapping.
  ASSIGN COMPONENT mapping-field OF STRUCTURE example TO <field>.
  IF sy-subrc <> 0.
    CONTINUE.
  ENDIF.

  <field> = mapping-value.
ENDLOOP.

 

Eine noch recht neue Variante ist der Zusatz ELSE UNASSIGN. Sollte es nun zu einem Fehler kommen, dann wird das Feldsymbol initialisiert und es kann damit nicht der falsche Wert überschrieben werden. In so einem Fall können wir dann auch ohne der SUBRC prüfen, ob das Element gesetzt ist. Damit sind wir nicht mehr abhängig von dem Systemfeld, sondern können auf das Element direkt verweisen.

LOOP AT get_mappings( ) INTO mapping.
  ASSIGN COMPONENT mapping-field OF STRUCTURE example TO <field> ELSE UNASSIGN.
  IF <field> IS NOT ASSIGNED.
    CONTINUE.
  ENDIF.

  <field> = mapping-value.
ENDLOOP.

 

Ergebnis

Schauen wir uns das Ergebnis der drei Varianten einmal an. Die Spalte C bleibt immer leer und nur im ersten Fall hat die Spalte B einen falschen Wert. Daher solltest du bei solchen Situationen immer auf ein sauberes Fehlerhandling achten.

 

Zuweisung

Schauen wir uns noch zwei Zuweisungen im Kontext von Referenzen an. In älteren Releases musst du eine Referenz meist erst einem Feldsymbol zuweisen, bevor du zum Beispiel die Tabelle verarbeiten kannst. Dabei muss eigentlich auch das Feldsymbol vom Typ TABLE sein, da sonst der Compiler bereits einen Fehler ausgibt.

ASSIGN local_reference->* TO FIELD-SYMBOL(<table>).

LOOP AT <table> ASSIGNING <line>.
  out->write( <line> ).
ENDLOOP.

 

In einem aktuellen Release kannst du dir das Sparen und direkt über die Referenz gehen. Hier wird erst zur Laufzeit geschaut, ob es sich bei der Referenz um eine Tabelle handelt.

LOOP AT local_reference->* ASSIGNING <line>.
  out->write( <line> ).
ENDLOOP.

 

Neuerungen

In diesem Artikel haben wir zusätzlich noch drei Neuerungen und Besonderheiten eingebaut, die in aktuellen Releases möglich sind und was zuvor nicht wirklich funktionierte.

  • Groß- und Kleinschreibung - Bei ASSIGN COMPONENT verwenden wir als Referenz die Felder in Kleinschreibung. Früher musste der Feldname immer in Großbuchstaben angegeben werden, da sonst das Feld nicht gefunden wurde. Mittlerweile ist das egal.
  • Inline Deklaration - Bei der Zuweisung der Referenz zum Feldsymbol haben wir eine Inline Deklaration verwendet. Diese wäre vom Typ ANY und könnte damit nicht für den Loop verwendet werden. In einem aktuellen Release ebenfalls kein Problem mehr.
  • Referenz - Ebenfalls bei der Zuweisung konnten wir direkt über die De-Referenzierung (->*) loopen, ohne Feldsymbol oder Zuweisung. Die direkte Verwendung von Referenzen wird damit einfacher, die Prüfung des Typs erfolgt erst zur Laufzeit.

 

Komplettes Beispiel

Möchtest du das Beispiel bei dir einmal nachvollziehen, dann findest du hier die komplette ausführbare Klasse. Wie oben bei den Besonderheiten beschrieben, kann es sein, dass es auf deinem Release nicht aktivierbar ist.

CLASS zcl_bs_demo_assign DEFINITION
  PUBLIC FINAL
  CREATE PUBLIC.

  PUBLIC SECTION.
    INTERFACES if_oo_adt_classrun.

  PRIVATE SECTION.
    TYPES: BEGIN OF simple_mapping,
             field TYPE string,
             value TYPE string,
           END OF simple_mapping.
    TYPES simple_mappings TYPE STANDARD TABLE OF simple_mapping WITH EMPTY KEY.

    TYPES: BEGIN OF simple_structure,
             a TYPE string,
             b TYPE string,
             c TYPE string,
             d TYPE string,
             e TYPE string,
           END OF simple_structure.
    TYPES simple_table TYPE STANDARD TABLE OF simple_structure WITH EMPTY KEY.

    METHODS get_examples
      RETURNING VALUE(result) TYPE simple_table.

    METHODS get_example
      RETURNING VALUE(result) TYPE simple_structure.

    METHODS get_mappings
      RETURNING VALUE(result) TYPE simple_mappings.

    METHODS assign_in_loop
      IMPORTING !out TYPE REF TO if_oo_adt_classrun_out.

    METHODS change_with_fieldsymbol
      IMPORTING !out TYPE REF TO if_oo_adt_classrun_out.

    METHODS loop_structure
      IMPORTING !out TYPE REF TO if_oo_adt_classrun_out.

    METHODS do_mapping
      IMPORTING !out TYPE REF TO if_oo_adt_classrun_out.

    METHODS assign_reference
      IMPORTING !out TYPE REF TO if_oo_adt_classrun_out.
ENDCLASS.


CLASS zcl_bs_demo_assign IMPLEMENTATION.
  METHOD if_oo_adt_classrun~main.
    assign_in_loop( out ).
    change_with_fieldsymbol( out ).
    loop_structure( out ).
    do_mapping( out ).
    assign_reference( out ).
  ENDMETHOD.


  METHOD get_examples.
    RETURN VALUE #( ( a = `1` b = `2` c = `3` d = `4` e = `5` )
                    ( a = `6` b = `7` c = `8` d = `9` e = `10` )
                    ( a = `11` b = `12` c = `13` d = `14` e = `15` )
                    ( a = `16` b = `17` c = `18` d = `19` e = `20` ) ).
  ENDMETHOD.


  METHOD get_example.
    RETURN VALUE #( a = `1`
                    b = `2`
                    c = `3`
                    d = `4`
                    e = `5` ).
  ENDMETHOD.


  METHOD get_mappings.
    RETURN VALUE #( ( field = `a` value = `101` )
                    ( field = `b` value = `102` )
                    ( field = `f` value = `103` )
                    ( field = `d` value = `104` )
                    ( field = `e` value = `105` ) ).
  ENDMETHOD.


  METHOD assign_in_loop.
    DATA(examples) = get_examples( ).

    LOOP AT examples ASSIGNING FIELD-SYMBOL(<line>).
      out->write( <line> ).
    ENDLOOP.
  ENDMETHOD.


  METHOD change_with_fieldsymbol.
    DATA(examples) = get_examples( ).

    LOOP AT examples ASSIGNING FIELD-SYMBOL(<line>).
      <line>-c = `New Value`.
    ENDLOOP.

    out->write( examples ).
  ENDMETHOD.


  METHOD loop_structure.
    DATA(example) = get_example( ).
    DATA(result) = ``.

    DO.
      ASSIGN COMPONENT sy-index OF STRUCTURE example TO FIELD-SYMBOL(<field>).
      IF sy-subrc <> 0.
        EXIT.
      ENDIF.

      result &&= <field>.
    ENDDO.

    out->write( result ).
  ENDMETHOD.


  METHOD do_mapping.
    DATA mapping TYPE zcl_bs_demo_assign=>simple_mapping.
    DATA example TYPE simple_structure.
    FIELD-SYMBOLS <field> TYPE data.

    LOOP AT get_mappings( ) INTO mapping.
      ASSIGN COMPONENT mapping-field OF STRUCTURE example TO <field>.
      <field> = mapping-value.
    ENDLOOP.

    out->write( example ).
    CLEAR example.

    LOOP AT get_mappings( ) INTO mapping.
      ASSIGN COMPONENT mapping-field OF STRUCTURE example TO <field>.
      IF sy-subrc <> 0.
        CONTINUE.
      ENDIF.

      <field> = mapping-value.
    ENDLOOP.

    out->write( example ).
    CLEAR example.

    LOOP AT get_mappings( ) INTO mapping.
      ASSIGN COMPONENT mapping-field OF STRUCTURE example TO <field> ELSE UNASSIGN.
      IF <field> IS NOT ASSIGNED.
        CONTINUE.
      ENDIF.

      <field> = mapping-value.
    ENDLOOP.

    out->write( example ).
  ENDMETHOD.


  METHOD assign_reference.
    FIELD-SYMBOLS <line> TYPE zcl_bs_demo_assign=>simple_structure.

    DATA(examples) = get_examples( ).
    DATA(local_reference) = REF #( examples ).

    ASSIGN local_reference->* TO FIELD-SYMBOL(<table>).

    LOOP AT <table> ASSIGNING <line>.
      out->write( <line> ).
    ENDLOOP.

    LOOP AT local_reference->* ASSIGNING <line>.
      out->write( <line> ).
    ENDLOOP.
  ENDMETHOD.
ENDCLASS.

 

Fazit

Der ASSIGN hilft auch heute noch zuverlässig generische Verarbeitungen sicherzustellen und schnell und zuverlässig Inhalte anzupassen. Am Anfang wirst du dich etwas bei der Verwendung eindenken müssen, doch die Vorteile von der Nutzung sind größer und werden dir schnell in Fleisch und Blut übergehen.


Enthaltene Themen:
Modernes ABAPASSIGNELSE
Kommentare (0)



Und weiter ...

Bist du zufrieden mit dem Inhalt des Artikels? Wir posten jeden Dienstag und Freitag neuen Content im Bereich ABAP und unregelmäßig in allen anderen Bereichen. Schaue bei unseren Tools und Apps vorbei, diese stellen wir kostenlos zur Verfügung.


ABAP - XCO Logging

Kategorie - ABAP

Die XCO Klassen sind Bestandteil der ABAP Cloud APIs und verfügen über zahlreiche Funktionen, die nicht immer so einfach zu verstehen sind. In diesem Artikel schauen wir uns das Logging Objekt im Detail an.

16.12.2025

ABAP - Der richtige Schlüssel

Kategorie - ABAP

Wie sieht es eigentlich bei der Nutzung von internen Tabellen aus? Immer noch TYPE TABLE in ABAP und die Tabelle ist fertig definiert?

14.11.2025

ABAP - XCO Reguläre Ausdrücke

Kategorie - ABAP

Schauen wir uns einmal die XCO Klassen für die regulären Ausdrücke an und wie damit recht einfach REGEX gegen Texte und Eingaben in ABAP Cloud absetzen kannst. Dabei vergleichen wir auch mit klassischem ABAP.

07.11.2025

ABAP - Escape

Kategorie - ABAP

Schauen wir uns in diesem Artikel einmal im Detail verschiedene Escape Varianten an, die du für die ABAP Entwicklung und Sicherheit im System benötigst.

07.10.2025

ABAP - Datum und Uhrzeit

Kategorie - ABAP

Schauen wir uns in diesem Artikel einmal die Datentypen für das Datum und die Uhrzeit in ABAP etwas genauer an. Hat sich zwischen den verschiedenen Releases etwas geändert und was solltest du heute noch nutzen?

03.10.2025