ABAP FIELD-SYMBOLS und ASSIGN: Dynamischer Feldzugriff

kategorie
ABAP-Statements
Veröffentlicht
autor
Johannes

Field-Symbols sind ein zentrales Konzept in ABAP für den dynamischen Zugriff auf Speicherbereiche. Im Gegensatz zu normalen Variablen, die Daten kopieren, zeigt ein Field-Symbol direkt auf den Speicherbereich einer anderen Variable – ähnlich wie Zeiger (Pointer) in anderen Programmiersprachen.

Grundkonzept

  • Ein Field-Symbol ist ein Platzhalter, der auf einen Speicherbereich zeigt
  • Es wird mit ASSIGN auf eine konkrete Variable “zugewiesen”
  • Änderungen am Field-Symbol ändern direkt die Originalvariable
  • Kein Kopieren von Daten = bessere Performance

Syntax

Field-Symbol deklarieren

" Mit konkretem Typ
FIELD-SYMBOLS: <fs_name> TYPE <typ>.
" Mit generischem Typ
FIELD-SYMBOLS: <fs_any> TYPE any.
FIELD-SYMBOLS: <fs_data> TYPE data.
FIELD-SYMBOLS: <fs_table> TYPE ANY TABLE.
FIELD-SYMBOLS: <fs_structure> TYPE any.
" Inline-Deklaration (ab 7.40)
ASSIGN variable TO FIELD-SYMBOL(<fs_inline>).

ASSIGN-Varianten

" Statische Zuweisung
ASSIGN <variable> TO <fs>.
" Dynamische Zuweisung (Feldname als String)
ASSIGN (lv_fieldname) TO <fs>.
" Komponente einer Struktur
ASSIGN COMPONENT <name_oder_index> OF STRUCTURE <struktur> TO <fs>.
" Mit Typ-Casting
ASSIGN <variable> TO <fs> CASTING TYPE <typ>.

Systemfelder

Nach ASSIGN:

  • sy-subrc:
    • 0: Zuweisung erfolgreich
    • 4: Zuweisung fehlgeschlagen (Variable existiert nicht oder Typ inkompatibel)

Beispiele

1. Grundlegende Verwendung

DATA: lv_number TYPE i VALUE 100.
FIELD-SYMBOLS: <fs_num> TYPE i.
" Field-Symbol auf Variable zuweisen
ASSIGN lv_number TO <fs_num>.
IF sy-subrc = 0.
" Änderung über Field-Symbol
<fs_num> = 200.
WRITE: / 'Original:', lv_number. " Ausgabe: 200
ENDIF.

2. Field-Symbol prüfen

FIELD-SYMBOLS: <fs> TYPE any.
" Vor Verwendung prüfen!
IF <fs> IS ASSIGNED.
" Field-Symbol zeigt auf gültige Daten
WRITE: / <fs>.
ELSE.
" Field-Symbol ist nicht zugewiesen
WRITE: / 'Field-Symbol nicht zugewiesen!'.
ENDIF.
" Zuweisung aufheben
UNASSIGN <fs>.

3. Field-Symbols mit internen Tabellen (LOOP)

Der häufigste Anwendungsfall – direkter Zugriff auf Tabellenzeilen:

TYPES: BEGIN OF ty_material,
matnr TYPE matnr,
menge TYPE i,
preis TYPE p DECIMALS 2,
END OF ty_material.
DATA: lt_materials TYPE TABLE OF ty_material.
lt_materials = VALUE #(
( matnr = 'MAT001' menge = 100 preis = '10.00' )
( matnr = 'MAT002' menge = 200 preis = '20.00' )
( matnr = 'MAT003' menge = 150 preis = '15.00' )
).
" Mit Field-Symbol: Direkter Zugriff, keine Kopie
FIELD-SYMBOLS: <fs_mat> TYPE ty_material.
LOOP AT lt_materials ASSIGNING <fs_mat>.
" Änderung wirkt direkt in der Tabelle
<fs_mat>-preis = <fs_mat>-preis * '1.1'. " 10% Erhöhung
ENDLOOP.
" Tabelle ist jetzt geändert!

4. Inline Field-Symbol Deklaration

" Modern (ab 7.40): Inline-Deklaration
LOOP AT lt_materials ASSIGNING FIELD-SYMBOL(<fs_inline>).
<fs_inline>-menge = <fs_inline>-menge + 50.
ENDLOOP.
" Auch mit READ TABLE
READ TABLE lt_materials ASSIGNING FIELD-SYMBOL(<fs_read>)
WITH KEY matnr = 'MAT001'.
IF sy-subrc = 0.
<fs_read>-preis = 99.
ENDIF.

5. Dynamischer Zugriff auf Strukturkomponenten

TYPES: BEGIN OF ty_person,
vorname TYPE string,
nachname TYPE string,
alter TYPE i,
END OF ty_person.
DATA: ls_person TYPE ty_person.
FIELD-SYMBOLS: <fs_field> TYPE any.
ls_person = VALUE #( vorname = 'Max' nachname = 'Müller' alter = 30 ).
" Zugriff über Komponentenindex
DO 3 TIMES.
ASSIGN COMPONENT sy-index OF STRUCTURE ls_person TO <fs_field>.
IF sy-subrc = 0.
WRITE: / 'Feld', sy-index, ':', <fs_field>.
ENDIF.
ENDDO.
" Zugriff über Komponentenname (als String)
DATA: lv_fieldname TYPE string VALUE 'NACHNAME'.
ASSIGN COMPONENT lv_fieldname OF STRUCTURE ls_person TO <fs_field>.
IF sy-subrc = 0.
WRITE: / 'Nachname:', <fs_field>.
ENDIF.

6. Dynamischer Variablenzugriff

DATA: lv_var1 TYPE string VALUE 'Wert 1',
lv_var2 TYPE string VALUE 'Wert 2',
lv_name TYPE string.
FIELD-SYMBOLS: <fs_dynamic> TYPE any.
" Variablenname dynamisch aus String
lv_name = 'LV_VAR1'.
ASSIGN (lv_name) TO <fs_dynamic>.
IF sy-subrc = 0.
WRITE: / 'Dynamisch:', <fs_dynamic>. " Wert 1
ENDIF.
" Auch für globale Variablen mit vollem Pfad
" ASSIGN ('(PROGRAMNAME)GLOBALVAR') TO <fs>.

7. CASTING - Typ-Konvertierung

DATA: lv_hex TYPE x LENGTH 4 VALUE '41424344'.
FIELD-SYMBOLS: <fs_char> TYPE c.
" Hex-Daten als Zeichen interpretieren
ASSIGN lv_hex TO <fs_char> CASTING TYPE c.
WRITE: / <fs_char>. " Ausgabe: ABCD
" Casting mit Strukturen
DATA: lv_raw TYPE x LENGTH 8.
FIELD-SYMBOLS: <fs_struct> TYPE ty_small_struct.
ASSIGN lv_raw TO <fs_struct> CASTING.

8. Generische Field-Symbols

FIELD-SYMBOLS: <fs_any> TYPE any, " Beliebiger Datentyp
<fs_data> TYPE data, " Beliebige Daten (nicht Objekte)
<fs_table> TYPE ANY TABLE. " Beliebige interne Tabelle
DATA: lt_any TYPE TABLE OF string.
" Generisches Field-Symbol für Tabellen
ASSIGN lt_any TO <fs_table>.
IF <fs_table> IS ASSIGNED.
LOOP AT <fs_table> ASSIGNING <fs_any>.
WRITE: / <fs_any>.
ENDLOOP.
ENDIF.

9. Field-Symbol auf Tabellenzeile mit Index

DATA: lt_data TYPE TABLE OF string.
lt_data = VALUE #( ( `Eins` ) ( `Zwei` ) ( `Drei` ) ).
FIELD-SYMBOLS: <fs_line> TYPE string.
" Direkter Zugriff auf Zeile 2
ASSIGN lt_data[ 2 ] TO <fs_line>.
IF sy-subrc = 0.
<fs_line> = 'GEÄNDERT'.
ENDIF.
" lt_data enthält jetzt: Eins, GEÄNDERT, Drei

10. Verschachtelte Strukturen dynamisch durchlaufen

DATA: lo_struct_descr TYPE REF TO cl_abap_structdescr,
lt_components TYPE abap_compdescr_tab.
FIELD-SYMBOLS: <fs_comp> TYPE abap_compdescr,
<fs_val> TYPE any.
" Strukturbeschreibung ermitteln
lo_struct_descr ?= cl_abap_typedescr=>describe_by_data( ls_person ).
lt_components = lo_struct_descr->components.
" Alle Komponenten durchlaufen
LOOP AT lt_components ASSIGNING <fs_comp>.
ASSIGN COMPONENT <fs_comp>-name OF STRUCTURE ls_person TO <fs_val>.
IF sy-subrc = 0.
WRITE: / <fs_comp>-name, '=', <fs_val>.
ENDIF.
ENDLOOP.

Field-Symbol vs. INTO (Performance)

AspektASSIGNING (Field-Symbol)INTO (Arbeitsbereich)
DatenkopieNeinJa
PerformanceSchnellerLangsamer
ÄnderungenDirekt in TabelleErfordert MODIFY
SpeicherMinimalZusätzlicher Speicher
" LANGSAM: Kopieren und zurückschreiben
LOOP AT lt_materials INTO ls_material.
ls_material-preis = ls_material-preis * 2.
MODIFY lt_materials FROM ls_material.
ENDLOOP.
" SCHNELL: Direkter Zugriff
LOOP AT lt_materials ASSIGNING <fs_mat>.
<fs_mat>-preis = <fs_mat>-preis * 2.
ENDLOOP.

Häufige Fehler

1. Nicht zugewiesenes Field-Symbol verwenden

FIELD-SYMBOLS: <fs> TYPE any.
" FEHLER: Field-Symbol nicht zugewiesen!
" WRITE: / <fs>. " Runtime Error!
" RICHTIG: Immer prüfen
IF <fs> IS ASSIGNED.
WRITE: / <fs>.
ENDIF.

2. Field-Symbol nach Tabellenänderung ungültig

LOOP AT lt_data ASSIGNING FIELD-SYMBOL(<fs>).
" VORSICHT: DELETE kann das Field-Symbol ungültig machen!
IF <fs>-status = 'X'.
DELETE lt_data. " <fs> zeigt jetzt ins Nichts!
ENDIF.
ENDLOOP.

3. Typ-Inkompatibilität

DATA: lv_string TYPE string VALUE 'Test'.
FIELD-SYMBOLS: <fs_int> TYPE i.
" FEHLER: Inkompatible Typen
ASSIGN lv_string TO <fs_int>.
IF sy-subrc <> 0.
WRITE: / 'Zuweisung fehlgeschlagen!'.
ENDIF.

Wichtige Hinweise / Best Practice

  • Prüfen Sie immer sy-subrc nach ASSIGN oder IS ASSIGNED vor Verwendung.
  • Verwenden Sie ASSIGNING in LOOP AT statt INTO für bessere Performance.
  • Field-Symbols sind ideal für dynamische Programmierung.
  • Nutzen Sie die Inline-Deklaration (FIELD-SYMBOL(<fs>)) für kürzeren Code.
  • Bei generischen Typen (TYPE any) ist CASTING oft erforderlich.
  • Field-Symbols können ungültig werden, wenn die Originaldaten gelöscht werden.
  • Für Objektreferenzen verwenden Sie stattdessen Datenreferenzen.
  • Kombinieren Sie mit READ TABLE für effizienten Einzelzugriff.