ABAP MODIFY Anweisung: Zeilen in internen Tabellen ändern

kategorie
ABAP-Statements
Veröffentlicht
autor
Johannes

Die MODIFY-Anweisung wird in ABAP verwendet, um bestehende Zeilen in internen Tabellen zu ändern. Sie kann eine einzelne Zeile (per Index oder Schlüssel) oder mehrere Zeilen gleichzeitig (mit WHERE-Bedingung) aktualisieren. Wenn die Zeile nicht existiert, kann MODIFY sie je nach Variante auch einfügen.

Syntax

Es gibt mehrere Varianten der MODIFY-Anweisung:

1. Zeile per Index ändern

MODIFY <interne_tabelle> FROM <arbeitsbereich> INDEX <index>
[TRANSPORTING <komponente1> <komponente2> ...].

2. Zeile per Tabellenschlüssel ändern oder einfügen

MODIFY TABLE <interne_tabelle> FROM <arbeitsbereich>
[TRANSPORTING <komponente1> <komponente2> ...].

3. Mehrere Zeilen mit WHERE-Bedingung ändern

MODIFY <interne_tabelle> FROM <arbeitsbereich>
TRANSPORTING <komponente1> [<komponente2> ...]
WHERE <bedingung>.

4. Aktuelle Zeile im LOOP ändern

LOOP AT <interne_tabelle> INTO <arbeitsbereich>.
" <arbeitsbereich> ändern
MODIFY <interne_tabelle> FROM <arbeitsbereich>.
ENDLOOP.

Bestandteile

  • <interne_tabelle>: Die Tabelle, deren Zeilen geändert werden sollen.
  • <arbeitsbereich>: Eine Struktur mit den neuen Werten. Muss zum Zeilentyp der Tabelle kompatibel sein.
  • INDEX <index>: Die Position der zu ändernden Zeile (nur bei Standardtabellen und sortierten Tabellen).
  • TABLE: Kennzeichnet die Variante mit Schlüsselsuche. Die Zeile wird anhand des Primärschlüssels gesucht.
  • TRANSPORTING <komponenten>: Beschränkt die Änderung auf die angegebenen Komponenten. Andere Felder bleiben unverändert.
  • WHERE <bedingung>: Ändert alle Zeilen, die die Bedingung erfüllen.

Systemfelder

Nach einem MODIFY werden folgende Systemfelder gesetzt:

  • sy-subrc:

    • 0: Zeile(n) erfolgreich geändert (oder eingefügt bei MODIFY TABLE).
    • 4: Keine passende Zeile gefunden (bei INDEX oder TABLE).
  • sy-tabix: Enthält den Index der geänderten Zeile (bei Einzelzeilenoperationen auf Index-Tabellen).

Funktionsweise nach Variante

MODIFY … INDEX

Ändert die Zeile an der angegebenen Indexposition. Der gesamte Inhalt des Arbeitsbereichs wird in die Zeile kopiert (außer bei TRANSPORTING).

" Zeile 3 komplett ersetzen
MODIFY lt_data FROM ls_new_data INDEX 3.
" Nur bestimmte Felder in Zeile 3 ändern
MODIFY lt_data FROM ls_new_data INDEX 3 TRANSPORTING field1 field2.

MODIFY TABLE

Sucht die Zeile anhand des Primärschlüssels im Arbeitsbereich:

  • Gefunden: Die Zeile wird aktualisiert.
  • Nicht gefunden: Die Zeile wird eingefügt (wie INSERT).
" Sucht nach Schlüssel und ändert oder fügt ein
MODIFY TABLE lt_customers FROM ls_customer.

MODIFY … WHERE

Ändert alle Zeilen, die die WHERE-Bedingung erfüllen. TRANSPORTING ist hier Pflicht.

" Alle Zeilen mit status = 'OLD' ändern
MODIFY lt_orders FROM ls_update
TRANSPORTING status
WHERE status = 'OLD'.

MODIFY im LOOP (ohne INDEX)

Innerhalb eines LOOP AT ... INTO kann MODIFY ohne INDEX verwendet werden – es ändert dann automatisch die aktuelle Zeile.

LOOP AT lt_data INTO ls_data.
ls_data-field = 'Neuer Wert'.
MODIFY lt_data FROM ls_data.
ENDLOOP.

Besser: Verwenden Sie ASSIGNING im Loop, um direkte Änderungen ohne MODIFY zu ermöglichen.

Beispiele

1. Zeile per Index ändern

TYPES: BEGIN OF ty_product,
id TYPE i,
name TYPE string,
price TYPE p DECIMALS 2,
END OF ty_product.
DATA: lt_products TYPE STANDARD TABLE OF ty_product WITH EMPTY KEY,
ls_product TYPE ty_product.
" Tabelle füllen
lt_products = VALUE #(
( id = 1 name = 'Laptop' price = '999.00' )
( id = 2 name = 'Maus' price = '29.99' )
( id = 3 name = 'Tastatur' price = '79.00' )
).
" Zeile 2 komplett ersetzen
ls_product = VALUE #( id = 2 name = 'Gaming-Maus' price = '59.99' ).
MODIFY lt_products FROM ls_product INDEX 2.
IF sy-subrc = 0.
WRITE: / 'Zeile 2 geändert.'.
ENDIF.

2. Nur bestimmte Felder ändern (TRANSPORTING)

" Nur den Preis in Zeile 1 ändern
ls_product-price = '899.00'.
MODIFY lt_products FROM ls_product INDEX 1 TRANSPORTING price.
" Name und ID bleiben unverändert
" Siehe auch: /read-table-statement/
READ TABLE lt_products INTO ls_product INDEX 1.
WRITE: / 'Produkt:', ls_product-name, 'Preis:', ls_product-price.
" Ausgabe: Laptop 899.00

3. MODIFY TABLE (Schlüsselbasiert)

TYPES: BEGIN OF ty_customer,
id TYPE i,
name TYPE string,
city TYPE string,
END OF ty_customer.
DATA: lt_customers TYPE HASHED TABLE OF ty_customer WITH UNIQUE KEY id,
ls_customer TYPE ty_customer.
" Tabelle füllen
lt_customers = VALUE #(
( id = 1 name = 'Müller GmbH' city = 'Berlin' )
( id = 2 name = 'Schmidt AG' city = 'München' )
).
" Existierenden Kunden ändern (ID 1 existiert)
ls_customer = VALUE #( id = 1 name = 'Müller & Co. GmbH' city = 'Berlin' ).
MODIFY TABLE lt_customers FROM ls_customer.
IF sy-subrc = 0.
WRITE: / 'Kunde 1 geändert.'.
ENDIF.
" Neuen Kunden einfügen (ID 3 existiert nicht)
ls_customer = VALUE #( id = 3 name = 'Weber KG' city = 'Hamburg' ).
MODIFY TABLE lt_customers FROM ls_customer.
WRITE: / 'Anzahl Kunden:', lines( lt_customers ). " Ausgabe: 3

4. Mehrere Zeilen mit WHERE ändern

TYPES: BEGIN OF ty_order,
order_id TYPE i,
status TYPE string,
amount TYPE p DECIMALS 2,
END OF ty_order.
DATA: lt_orders TYPE STANDARD TABLE OF ty_order WITH EMPTY KEY,
ls_update TYPE ty_order.
lt_orders = VALUE #(
( order_id = 1 status = 'NEU' amount = '100.00' )
( order_id = 2 status = 'NEU' amount = '250.00' )
( order_id = 3 status = 'OFFEN' amount = '180.00' )
( order_id = 4 status = 'NEU' amount = '320.00' )
).
" Alle Bestellungen mit Status 'NEU' auf 'IN_BEARBEITUNG' setzen
ls_update-status = 'IN_BEARBEITUNG'.
MODIFY lt_orders FROM ls_update
TRANSPORTING status
WHERE status = 'NEU'.
" Ergebnis: 3 Zeilen geändert (order_id 1, 2, 4)
LOOP AT lt_orders INTO DATA(ls_order).
WRITE: / ls_order-order_id, ls_order-status.
ENDLOOP.

5. MODIFY im LOOP mit INTO

DATA: ls_prod TYPE ty_product.
" Alle Preise um 10% erhöhen
LOOP AT lt_products INTO ls_prod.
ls_prod-price = ls_prod-price * '1.1'.
MODIFY lt_products FROM ls_prod.
ENDLOOP.

6. Bessere Alternative: LOOP mit ASSIGNING

FIELD-SYMBOLS: <fs_prod> TYPE ty_product.
" Alle Preise um 10% erhöhen – ohne MODIFY
LOOP AT lt_products ASSIGNING <fs_prod>.
<fs_prod>-price = <fs_prod>-price * '1.1'.
ENDLOOP.
" Änderungen sind sofort wirksam, kein MODIFY nötig!

7. MODIFY TABLE mit TRANSPORTING

" Nur die Stadt eines Kunden ändern (Schlüsselsuche)
ls_customer-id = 2. " Schlüssel für die Suche
ls_customer-city = 'Köln'. " Neuer Wert
MODIFY TABLE lt_customers FROM ls_customer TRANSPORTING city.
IF sy-subrc = 0.
WRITE: / 'Stadt von Kunde 2 geändert.'.
ENDIF.

Verhalten nach Tabellentyp

TabellentypINDEXTABLEWHERE
STANDARD TABLEJaJa (lineare Suche)Ja
SORTED TABLEJaJa (binäre Suche)Ja
HASHED TABLENeinJa (Hash-Lookup)Ja

Wichtig bei sortierten Tabellen: Wenn Sie Schlüsselfelder ändern, kann dies die Sortierreihenfolge verletzen und zu einem Laufzeitfehler führen!

" Gefährlich bei SORTED TABLE mit KEY id:
ls_customer-id = 999. " Schlüsselfeld ändern
MODIFY TABLE lt_sorted_customers FROM ls_customer. " Kann Dump verursachen!

Abgrenzung zu anderen Anweisungen

MODIFY vs. ASSIGNING im LOOP

AspektMODIFY im LOOPASSIGNING
SyntaxMehr CodeKompakter
PerformanceLangsamer (Kopieren)Schneller (Direktzugriff)
AnwendungLegacy-CodeEmpfohlen
" Mit MODIFY (veraltet)
LOOP AT lt_data INTO ls_data.
ls_data-field = 'X'.
MODIFY lt_data FROM ls_data.
ENDLOOP.
" Mit ASSIGNING (empfohlen)
LOOP AT lt_data ASSIGNING FIELD-SYMBOL(<fs>).
<fs>-field = 'X'.
ENDLOOP.

MODIFY vs. INSERT und APPEND

  • MODIFY TABLE: Ändert existierende Zeile ODER fügt neue ein (Upsert).
  • INSERT: Fügt nur ein, schlägt fehl wenn Schlüssel existiert.
  • APPEND: Fügt immer am Ende einer Standardtabelle an.

MODIFY vs. UPDATE (Datenbank)

  • MODIFY: Für interne Tabellen (im Arbeitsspeicher).
  • UPDATE: Für Datenbanktabellen (persistente Daten).

Für das Suchen einer Zeile vor dem Ändern siehe READ TABLE.

Performance-Tipps

  1. ASSIGNING statt MODIFY im LOOP: Vermeiden Sie LOOP ... INTO mit anschließendem MODIFY. Nutzen Sie stattdessen ASSIGNING für direkten Schreibzugriff.

  2. TRANSPORTING bei großen Strukturen: Wenn nur wenige Felder geändert werden, beschränken Sie mit TRANSPORTING die zu kopierenden Daten.

  3. WHERE für Massenänderungen: MODIFY ... WHERE ist effizienter als ein manueller Loop mit Einzeländerungen.

  4. Schlüsselfelder nicht ändern: Bei sortierten und Hash-Tabellen sollten Schlüsselfelder nicht geändert werden. Stattdessen: Zeile löschen und neu einfügen (siehe APPEND oder INSERT).

Wichtige Hinweise / Best Practice

  • Prüfen Sie sy-subrc nach MODIFY mit INDEX oder TABLE, um sicherzustellen, dass die Zeile gefunden wurde.
  • Bevorzugen Sie ASSIGNING im LOOP AT für direkte Änderungen – das ist performanter und eleganter als MODIFY.
  • Verwenden Sie TRANSPORTING, wenn nur bestimmte Felder geändert werden sollen.
  • MODIFY TABLE ist ein “Upsert” – es fügt ein, wenn die Zeile nicht existiert.
  • Ändern Sie niemals Schlüsselfelder bei sortierten oder Hash-Tabellen direkt.
  • Bei MODIFY ... WHERE ist TRANSPORTING Pflicht.
  • Diese MODIFY-Anweisung ist für interne Tabellen. Für Datenbanktabellen siehe INSERT, UPDATE, DELETE.