ABAP DELETE für interne Tabellen: Zeilen löschen

kategorie
ABAP-Statements
Veröffentlicht
autor
Johannes

Die DELETE-Anweisung für interne Tabellen entfernt eine oder mehrere Zeilen aus einer internen Tabelle. Es gibt verschiedene Varianten: Löschen per Index, per Schlüssel, mit WHERE-Bedingung oder das Entfernen von Duplikaten.

Syntax

1. Zeile per Index löschen

DELETE <interne_tabelle> INDEX <index>.

2. Zeile per Schlüssel löschen

DELETE TABLE <interne_tabelle> FROM <arbeitsbereich>.
DELETE TABLE <interne_tabelle> WITH TABLE KEY <schlüssel> = <wert>.

3. Mehrere Zeilen mit WHERE löschen

DELETE <interne_tabelle> WHERE <bedingung>.

4. Zeile im aktuellen LOOP löschen

LOOP AT <interne_tabelle> ...
DELETE <interne_tabelle>. " Löscht aktuelle Zeile
ENDLOOP.

5. Duplikate entfernen

DELETE ADJACENT DUPLICATES FROM <interne_tabelle>
[COMPARING <felder> | ALL FIELDS]
[USING KEY <schlüssel>].

Systemfelder

Nach DELETE:

  • sy-subrc:

    • 0: Mindestens eine Zeile gelöscht
    • 4: Keine passende Zeile gefunden
  • sy-tabix: Bei DELETE ... INDEX unverändert; sonst undefiniert

Beispiele

1. Zeile per Index löschen

DATA: lt_names TYPE TABLE OF string.
lt_names = VALUE #( ( `Anna` ) ( `Bernd` ) ( `Clara` ) ( `David` ) ).
" Zweite Zeile löschen
DELETE lt_names INDEX 2.
" Ergebnis: Anna, Clara, David
LOOP AT lt_names INTO DATA(lv_name).
WRITE: / lv_name.
ENDLOOP.

2. Erste und letzte Zeile löschen

DATA: lt_data TYPE TABLE OF i.
lt_data = VALUE #( ( 10 ) ( 20 ) ( 30 ) ( 40 ) ( 50 ) ).
" Erste Zeile löschen
DELETE lt_data INDEX 1.
" Letzte Zeile löschen
DELETE lt_data INDEX lines( lt_data ).
" Ergebnis: 20, 30, 40

3. Zeile per Schlüssel löschen (FROM)

TYPES: BEGIN OF ty_customer,
id TYPE i,
name TYPE string,
END OF ty_customer.
DATA: lt_customers TYPE HASHED TABLE OF ty_customer WITH UNIQUE KEY id,
ls_customer TYPE ty_customer.
lt_customers = VALUE #(
( id = 1 name = 'Müller' )
( id = 2 name = 'Schmidt' )
( id = 3 name = 'Weber' )
).
" Kunde mit ID 2 löschen
ls_customer-id = 2.
DELETE TABLE lt_customers FROM ls_customer.
IF sy-subrc = 0.
WRITE: / 'Kunde gelöscht.'.
ELSE.
WRITE: / 'Kunde nicht gefunden.'.
ENDIF.

4. Zeile per Schlüssel löschen (WITH TABLE KEY)

" Direkter Schlüsselzugriff
DELETE TABLE lt_customers WITH TABLE KEY id = 3.
IF sy-subrc = 0.
WRITE: / 'Kunde 3 gelöscht.'.
ENDIF.

5. Mehrere Zeilen mit WHERE löschen

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 TABLE OF ty_order.
lt_orders = VALUE #(
( order_id = 1 status = 'OPEN' amount = '100.00' )
( order_id = 2 status = 'CANCELLED' amount = '200.00' )
( order_id = 3 status = 'OPEN' amount = '150.00' )
( order_id = 4 status = 'CANCELLED' amount = '300.00' )
( order_id = 5 status = 'COMPLETED' amount = '250.00' )
).
" Alle stornierten Bestellungen löschen
DELETE lt_orders WHERE status = 'CANCELLED'.
WRITE: / 'Gelöschte Zeilen:', sy-dbcnt.
WRITE: / 'Verbleibende Zeilen:', lines( lt_orders ).
" Ergebnis: order_id 1, 3, 5 bleiben

6. Komplexe WHERE-Bedingung

" Mehrere Bedingungen kombinieren
DELETE lt_orders WHERE status = 'OPEN'
AND amount < 120.
" Mit OR
DELETE lt_orders WHERE status = 'CANCELLED'
OR amount = 0.
" Mit IN
DATA: lt_status TYPE RANGE OF string.
lt_status = VALUE #( ( sign = 'I' option = 'EQ' low = 'CANCELLED' )
( sign = 'I' option = 'EQ' low = 'REJECTED' ) ).
DELETE lt_orders WHERE status IN lt_status.

7. Zeile im LOOP löschen

" ACHTUNG: DELETE im LOOP ist erlaubt, aber Vorsicht bei Field-Symbols!
DATA: lt_numbers TYPE TABLE OF i.
lt_numbers = VALUE #( ( 1 ) ( 2 ) ( 3 ) ( 4 ) ( 5 ) ( 6 ) ).
" Alle geraden Zahlen löschen
LOOP AT lt_numbers INTO DATA(lv_num).
IF lv_num MOD 2 = 0.
DELETE lt_numbers.
ENDIF.
ENDLOOP.
" Ergebnis: 1, 3, 5

8. DELETE im LOOP mit ASSIGNING (Vorsicht!)

" Mit ASSIGNING ist DELETE problematisch!
LOOP AT lt_numbers ASSIGNING FIELD-SYMBOL(<fs_num>).
IF <fs_num> MOD 2 = 0.
DELETE lt_numbers.
" ACHTUNG: <fs_num> zeigt jetzt auf ungültige Daten!
" Weitere Zugriffe auf <fs_num> können Fehler verursachen.
ENDIF.
ENDLOOP.
" BESSER: Mit INTO arbeiten oder WHERE verwenden
DELETE lt_numbers WHERE table_line MOD 2 = 0.

9. DELETE ADJACENT DUPLICATES - Duplikate entfernen

DATA: lt_names TYPE TABLE OF string.
lt_names = VALUE #(
( `Anna` ) ( `Anna` ) ( `Bernd` ) ( `Clara` )
( `Clara` ) ( `Clara` ) ( `David` )
).
" Aufeinanderfolgende Duplikate entfernen
DELETE ADJACENT DUPLICATES FROM lt_names.
" Ergebnis: Anna, Bernd, Clara, David
LOOP AT lt_names INTO DATA(lv_name).
WRITE: / lv_name.
ENDLOOP.

10. DELETE ADJACENT DUPLICATES nach SORT

TYPES: BEGIN OF ty_product,
category TYPE string,
name TYPE string,
price TYPE p DECIMALS 2,
END OF ty_product.
DATA: lt_products TYPE TABLE OF ty_product.
lt_products = VALUE #(
( category = 'A' name = 'Prod1' price = 10 )
( category = 'B' name = 'Prod2' price = 20 )
( category = 'A' name = 'Prod3' price = 15 )
( category = 'A' name = 'Prod1' price = 10 ) " Duplikat
( category = 'B' name = 'Prod2' price = 25 ) " Teilweise Duplikat
).
" WICHTIG: Erst sortieren!
SORT lt_products BY category name.
" Duplikate nach category und name entfernen
DELETE ADJACENT DUPLICATES FROM lt_products
COMPARING category name.
" Ergebnis: Nur eindeutige category/name Kombinationen

11. COMPARING ALL FIELDS

" Nur exakte Duplikate entfernen (alle Felder gleich)
SORT lt_products BY category name price.
DELETE ADJACENT DUPLICATES FROM lt_products
COMPARING ALL FIELDS.

12. USING KEY für Sekundärschlüssel

DATA: lt_data TYPE SORTED TABLE OF ty_product
WITH UNIQUE KEY category name
WITH NON-UNIQUE SORTED KEY by_price COMPONENTS price.
" Duplikate nach Preis entfernen
DELETE ADJACENT DUPLICATES FROM lt_data
USING KEY by_price.

13. Bereich löschen (FROM … TO)

DATA: lt_nums TYPE TABLE OF i.
lt_nums = VALUE #( ( 1 ) ( 2 ) ( 3 ) ( 4 ) ( 5 ) ( 6 ) ( 7 ) ( 8 ) ).
" Zeilen 3 bis 6 löschen
DELETE lt_nums FROM 3 TO 6.
" Ergebnis: 1, 2, 7, 8

14. DELETE für verschiedene Tabellentypen

TabellentypINDEXFROM waWITH TABLE KEYWHERE
STANDARDJaJa (linear)JaJa
SORTEDJaJa (binär)JaJa
HASHEDNeinJa (hash)JaJa
" STANDARD TABLE: Alle Varianten möglich
DATA: lt_standard TYPE STANDARD TABLE OF ty_customer.
DELETE lt_standard INDEX 1.
DELETE TABLE lt_standard FROM ls_customer.
DELETE lt_standard WHERE name = 'Test'.
" HASHED TABLE: Kein INDEX!
DATA: lt_hashed TYPE HASHED TABLE OF ty_customer WITH UNIQUE KEY id.
" DELETE lt_hashed INDEX 1. " FEHLER!
DELETE TABLE lt_hashed WITH TABLE KEY id = 1. " OK
DELETE lt_hashed WHERE name = 'Test'. " OK

Vergleich: DELETE vs. CLEAR vs. FREE

AnweisungWirkung
DELETE itab ...Entfernt bestimmte Zeilen
CLEAR itabEntfernt alle Zeilen, behält Speicher
FREE itabEntfernt alle Zeilen, gibt Speicher frei
" Bestimmte Zeilen entfernen
DELETE lt_data WHERE status = 'X'.
" Alle Zeilen entfernen (Speicher behalten)
CLEAR lt_data.
" Alle Zeilen entfernen und Speicher freigeben
FREE lt_data.

Performance-Tipps

  1. WHERE statt LOOP mit DELETE:

    " LANGSAM
    LOOP AT lt_data INTO ls_data.
    IF ls_data-status = 'X'.
    DELETE lt_data.
    ENDIF.
    ENDLOOP.
    " SCHNELLER
    DELETE lt_data WHERE status = 'X'.
  2. SORT vor ADJACENT DUPLICATES: DELETE ADJACENT DUPLICATES erkennt nur aufeinanderfolgende Duplikate. Sortieren Sie zuerst!

  3. Index-basiertes Löschen von hinten:

    " Beim Löschen mehrerer Zeilen per Index: Von hinten nach vorne
    DO 3 TIMES.
    DELETE lt_data INDEX lines( lt_data ).
    ENDDO.
  4. Effiziente Massenloschung: Für das Löschen vieler Zeilen ist DELETE ... WHERE effizienter als einzelne Löschungen.

Wichtige Hinweise / Best Practice

  • Prüfen Sie sy-subrc nach DELETE ... INDEX oder DELETE TABLE.
  • DELETE ... WHERE setzt sy-subrc = 0 auch wenn keine Zeile gelöscht wurde (aber sy-dbcnt = 0).
  • Sortieren Sie vor DELETE ADJACENT DUPLICATES.
  • Vorsicht beim Löschen im LOOP AT mit ASSIGNING – das Field-Symbol wird ungültig!
  • Bei HASHED TABLE ist DELETE ... INDEX nicht möglich.
  • Für Datenbanktabellen verwenden Sie DELETE FROM dbtab.
  • DELETE ADJACENT DUPLICATES entfernt nur benachbarte Duplikate.
  • Nutzen Sie SORT in Kombination mit DELETE ADJACENT DUPLICATES für eindeutige Listen.