Die COLLECT Anweisung in ABAP: Syntax, Beispiele & Tabellentypen

kategorie
ABAP-Statements
Veröffentlicht
autor
Johannes

Die COLLECT-Anweisung ist ein spezieller Befehl in ABAP, der zum Verdichten bzw. Aggregieren von Daten in einer * internen Tabelle* dient. Die Besonderheit von COLLECT ist:

  1. Es prüft, ob in der Zieltabelle bereits eine Zeile existiert, deren Schlüssel mit dem der hinzuzufügenden Zeile übereinstimmt. Der “Schlüssel” für COLLECT besteht dabei immer aus allen nicht-numerischen Feldern der Tabellenzeile (also alles außer Typ I, P, F, DECFLOAT16/34).
  2. Wenn eine Zeile mit identischem nicht-numerischen Schlüssel gefunden wird: Die Werte aller numerischen Felder der hinzuzufügenden Zeile werden zu den Werten der entsprechenden numerischen Felder der bereits vorhandenen Zeile hinzuaddiert.
  3. Wenn keine Zeile mit identischem nicht-numerischen Schlüssel gefunden wird: Die hinzuzufügende Zeile wird als * neuer Eintrag* in die Tabelle eingefügt (ähnlich wie bei [APPEND](/append-statement/) für Standardtabellen oder INSERT für Hash-Tabellen).

COLLECT ist also ideal, um Summen oder Zählungen über bestimmte Merkmale zu bilden (z.B. Gesamtmenge pro Material und Werk).

Syntax

COLLECT <wa> INTO <interne_tabelle>
[ASSIGNING <feldsymbol> | REFERENCE INTO <datenreferenz>].
  • COLLECT: Das ABAP-Schlüsselwort.
  • <wa>: Ein Arbeitsbereich (Struktur), der zum Zeilentyp der <interne_tabelle> kompatibel ist.
    • Die nicht-numerischen Felder in <wa> bilden den Schlüssel für die Suche/Aggregation.
    • Die numerischen Felder in <wa> enthalten die Werte, die ggf. zu einer bestehenden Zeile addiert werden.
  • INTO <interne_tabelle>: Die interne Zieltabelle, in der aggregiert oder eingefügt wird.
  • ASSIGNING <feldsymbol> / REFERENCE INTO <datenreferenz> (Optional): Nach der Operation zeigt das Feldsymbol bzw. die Datenreferenz auf die Zeile in der Tabelle, die entweder neu eingefügt oder deren numerische Werte gerade aktualisiert wurden. Dies ist nützlich für den direkten Zugriff auf das Ergebnis.

Funktionsweise und Verhalten nach Tabellentyp (Wichtig!)

Die Eignung und Effizienz von COLLECT hängt stark vom Typ der Zieltabelle ab:

1. Standardtabellen (STANDARD TABLE)

  • COLLECT ist erlaubt.
  • Die Suche nach einer Zeile mit passendem nicht-numerischen Schlüssel erfolgt durch sequenzielles Lesen der Tabelle. Dies kann bei großen Tabellen sehr langsam werden!
  • Wird kein passender Schlüssel gefunden, wird die Zeile aus <wa> am Ende der Tabelle angehängt (wie APPEND).
  • sy-tabix wird auf den Index der modifizierten oder neu angehängten Zeile gesetzt.

2. Hashed-Tabellen (HASHED TABLE)

  • COLLECT ist erlaubt und oft der effizienteste Anwendungsfall, ABER NUR WENN der eindeutige Schlüssel ( UNIQUE KEY) der Hash-Tabelle exakt aus allen nicht-numerischen Feldern der Zeilenstruktur besteht und * keine numerischen Felder* enthält.
  • Ist diese Bedingung erfüllt, nutzt COLLECT den Hash-Algorithmus für eine sehr schnelle Suche nach dem Schlüssel.
  • Wird kein passender Schlüssel gefunden, wird die Zeile eingefügt (wie INSERT).
  • sy-tabix ist hier undefiniert (meist 0), da der Index bei Hash-Tabellen keine Rolle spielt.
  • Achtung: Stimmt der definierte Schlüssel der Hash-Tabelle nicht mit dem impliziten COLLECT-Schlüssel (alle nicht-numerischen Felder) überein, führt die Verwendung von COLLECT zu einem Laufzeitfehler!

3. Sortierte Tabellen (SORTED TABLE)

  • Die Verwendung von COLLECT mit sortierten Tabellen ist dringend abzuraten und führt oft zu Laufzeitfehlern!
  • COLLECT ignoriert die definierte Sortierreihenfolge der Tabelle und arbeitet nur mit seinem eigenen impliziten Schlüssel (alle nicht-numerischen Felder). Das Einfügen oder Aggregieren kann die Sortierung verletzen und zu inkonsistenten Zuständen oder direkten Abbrüchen führen.
  • Für Aggregationen in sortierten Tabellen: Verwende stattdessen eine manuelle Logik mit READ TABLE <tabelle> WITH KEY ... BINARY SEARCH, gefolgt von MODIFY <tabelle> ... (wenn gefunden) oder INSERT <wa> INTO TABLE <tabelle> (wenn nicht gefunden).

Systemfelder

  • sy-subrc: Wird durch COLLECT normalerweise immer auf 0 gesetzt, egal ob eine Zeile aggregiert oder neu eingefügt wurde. Er ist daher kein guter Indikator dafür, was passiert ist.
  • sy-tabix: Sinnvoll nur bei Standardtabellen, wo er den Index der bearbeiteten/neu eingefügten Zeile enthält. Bei Hash-Tabellen ist er 0/undefiniert.

Beispiele

1. Aggregation in Standardtabelle (Menge pro Material)

TYPES: BEGIN OF ty_mat_quant,
material TYPE string, " Schlüssel (nicht-numerisch)
quantity TYPE i, " Wert (numerisch)
END OF ty_mat_quant.
DATA: lt_summary TYPE STANDARD TABLE OF ty_mat_quant,
ls_data TYPE ty_mat_quant.
ls_data = VALUE #( material = 'M-01' quantity = 10 ).
COLLECT ls_data INTO lt_summary.
ls_data = VALUE #( material = 'M-02' quantity = 5 ).
COLLECT ls_data INTO lt_summary.
ls_data = VALUE #( material = 'M-01' quantity = 7 ). " Wird zu M-01 addiert
COLLECT ls_data INTO lt_summary.
cl_demo_output=>display( lt_summary ).
" Ausgabe:
" Material | Quantity
" ---------|---------
" M-01 | 17
" M-02 | 5

2. Effiziente Aggregation in Hashed-Tabelle (Menge pro Material/Werk)

TYPES: BEGIN OF ty_stock,
matnr TYPE matnr, " Teil des Schlüssels
werks TYPE werks_d, " Teil des Schlüssels
menge TYPE i, " Wert
END OF ty_stock.
" Schlüssel der Hash-Tabelle MUSS den nicht-numerischen Feldern entsprechen!
DATA lt_stock_agg TYPE HASHED TABLE OF ty_stock
WITH UNIQUE KEY matnr werks.
DATA ls_stock TYPE ty_stock.
ls_stock = VALUE #( matnr = 'MAT1' werks = '1000' menge = 100 ).
COLLECT ls_stock INTO lt_stock_agg.
ls_stock = VALUE #( matnr = 'MAT2' werks = '1000' menge = 50 ).
COLLECT ls_stock INTO lt_stock_agg.
ls_stock = VALUE #( matnr = 'MAT1' werks = '1000' menge = 25 ). " Wird addiert
COLLECT ls_stock INTO lt_stock_agg.
ls_stock = VALUE #( matnr = 'MAT1' werks = '2000' menge = 200 ). " Neuer Eintrag
COLLECT ls_stock INTO lt_stock_agg.
cl_demo_output=>display( lt_stock_agg ).
" Ausgabe (Reihenfolge bei Hash nicht definiert):
" Matnr | Werks | Menge
" ------|-------|------
" MAT1 | 1000 | 125
" MAT2 | 1000 | 50
" MAT1 | 2000 | 200

3. Verwendung von ASSIGNING

FIELD-SYMBOLS: <fs_stock_line> LIKE LINE OF lt_stock_agg.
ls_stock = VALUE #( matnr = 'MAT1' werks = '1000' menge = 5 ).
COLLECT ls_stock INTO lt_stock_agg ASSIGNING <fs_stock_line>.
IF <fs_stock_line> IS ASSIGNED.
WRITE: / 'Aggregierte/Neue Zeile:', <fs_stock_line>-matnr, <fs_stock_line>-werks, 'Menge:', <fs_stock_line>-menge.
" Ausgabe z.B.: Aggregierte/Neue Zeile: MAT1 1000 Menge: 130 (wenn vorher 125 drin war)
ENDIF.

Wichtige Hinweise / Best Practice

  • COLLECT ist das spezielle Werkzeug für die Aggregation numerischer Werte basierend auf einem nicht-numerischen Schlüssel in internen Tabellen.
  • Es modifiziert die Zieltabelle direkt.
  • Für optimale Performance nutze COLLECT mit Hashed-Tabellen, deren Schlüssel korrekt definiert ist (Unique Key = alle nicht-numerischen Felder).
  • Verwende COLLECT nicht mit sortierten Tabellen – nutze stattdessen READ/MODIFY/INSERT.
  • Bei Standardtabellen bedenke die potenzielle Performance-Implikation bei großen Datenmengen.