Die READ TABLE-Anweisung dient dazu, eine einzelne, spezifische Zeile aus einer internen Tabelle zu lesen. Im Gegensatz zu LOOP AT, das alle oder mehrere Zeilen durchläuft, ist READ TABLE für den gezielten Zugriff auf genau eine Zeile optimiert – entweder über den Tabellenschlüssel, einen Index oder eine freie Suchbedingung.
Syntax
Es gibt verschiedene Varianten, um die gewünschte Zeile zu identifizieren:
1. Suche über Schlüsselfelder (WITH KEY)
READ TABLE <interne_tabelle> INTO <arbeitsbereich> | ASSIGNING <feldsymbol> | REFERENCE INTO <datenreferenz> WITH KEY <komponente1> = <wert1> [<komponente2> = <wert2> ...] [BINARY SEARCH].2. Suche über Tabellenschlüssel (WITH TABLE KEY)
READ TABLE <interne_tabelle> INTO <arbeitsbereich> | ASSIGNING <feldsymbol> | REFERENCE INTO <datenreferenz> WITH TABLE KEY <schlüsselkomponente1> = <wert1> [<schlüsselkomponente2> = <wert2> ...].3. Zugriff über Index (INDEX)
READ TABLE <interne_tabelle> INTO <arbeitsbereich> | ASSIGNING <feldsymbol> | REFERENCE INTO <datenreferenz> INDEX <index>.4. Suche mit freier Bedingung (WITH KEY ... COMPONENTS)
READ TABLE <interne_tabelle> INTO <arbeitsbereich> | ASSIGNING <feldsymbol> | REFERENCE INTO <datenreferenz> WITH KEY <tabellenkomponente> COMPONENTS <komponente1> = <wert1> [...].5. Nur Existenzprüfung ohne Datentransport
READ TABLE <interne_tabelle> TRANSPORTING NO FIELDS WITH KEY <komponente> = <wert>.Bestandteile
<interne_tabelle>: Die Tabelle, in der gesucht werden soll.INTO <arbeitsbereich>: Die gefundene Zeile wird in den Arbeitsbereich kopiert.ASSIGNING <feldsymbol>: Das Feldsymbol zeigt direkt auf die gefundene Zeile.REFERENCE INTO <datenreferenz>: Eine Datenreferenz auf die gefundene Zeile.WITH KEY: Suche über beliebige Komponenten (nicht zwingend der Tabellenschlüssel).WITH TABLE KEY: Suche über den definierten Primärschlüssel der Tabelle (optimiert).INDEX <index>: Direkter Zugriff auf die Zeile an der angegebenen Position.BINARY SEARCH: Binäre Suche (nur bei sortierten Standardtabellen – Tabelle muss sortiert sein!).TRANSPORTING NO FIELDS: Es werden keine Daten transportiert, nursy-subrcundsy-tabixgesetzt.
Systemfelder
Nach einem READ TABLE werden folgende Systemfelder gesetzt:
-
sy-subrc:0: Zeile wurde gefunden.4: Keine passende Zeile gefunden.8: (BeiBINARY SEARCH) Zeile nicht gefunden, abersy-tabixzeigt auf die Einfügeposition.
-
sy-tabix: Enthält den Index der gefundenen Zeile (bei Index-Tabellen). Bei Hash-Tabellen istsy-tabixnicht definiert.
Suchverhalten nach Tabellentyp
Das Suchverhalten und die Performance hängen vom Tabellentyp ab:
| Tabellentyp | WITH KEY | WITH TABLE KEY | INDEX | Performance |
|---|---|---|---|---|
| STANDARD TABLE | Lineare Suche O(n) | Lineare Suche O(n) | O(1) | Langsam bei großen Tabellen |
| SORTED TABLE | Binäre Suche O(log n) | Binäre Suche O(log n) | O(1) | Schnell |
| HASHED TABLE | Hash-Lookup O(1) | Hash-Lookup O(1) | Nicht möglich | Sehr schnell |
Beispiele
1. READ TABLE mit INTO (Kopie)
TYPES: BEGIN OF ty_customer, id TYPE i, name TYPE string, city TYPE string, END OF ty_customer.
DATA: lt_customers TYPE STANDARD TABLE OF ty_customer WITH EMPTY KEY, ls_customer TYPE ty_customer.
" Tabelle füllenlt_customers = VALUE #( ( id = 1 name = 'Müller GmbH' city = 'Berlin' ) ( id = 2 name = 'Schmidt AG' city = 'München' ) ( id = 3 name = 'Weber KG' city = 'Hamburg' )).
" Kunde mit ID 2 suchenREAD TABLE lt_customers INTO ls_customer WITH KEY id = 2.
IF sy-subrc = 0. WRITE: / 'Gefunden:', ls_customer-name, 'in', ls_customer-city. WRITE: / 'Index:', sy-tabix.ELSE. WRITE: / 'Kunde nicht gefunden.'.ENDIF.2. READ TABLE mit ASSIGNING (Direktzugriff)
FIELD-SYMBOLS: <fs_customer> TYPE ty_customer.
" Kunde suchen und direkt ändernREAD TABLE lt_customers ASSIGNING <fs_customer> WITH KEY id = 1.
IF sy-subrc = 0. " Änderung wirkt direkt in der Tabelle <fs_customer>-city = 'Frankfurt'. WRITE: / 'Stadt geändert zu:', <fs_customer>-city.ELSE. WRITE: / 'Kunde nicht gefunden.'.ENDIF.3. READ TABLE mit INDEX
" Erste Zeile lesenREAD TABLE lt_customers INTO ls_customer INDEX 1.
IF sy-subrc = 0. WRITE: / 'Erste Zeile:', ls_customer-name.ENDIF.
" Letzte Zeile lesenREAD TABLE lt_customers INTO ls_customer INDEX lines( lt_customers ).
IF sy-subrc = 0. WRITE: / 'Letzte Zeile:', ls_customer-name.ENDIF.4. READ TABLE mit BINARY SEARCH
" WICHTIG: Tabelle muss nach dem Suchfeld sortiert sein!" Siehe: /sort-statement/SORT lt_customers BY id.
READ TABLE lt_customers INTO ls_customer WITH KEY id = 2 BINARY SEARCH.
IF sy-subrc = 0. WRITE: / 'Gefunden (binär):', ls_customer-name.ENDIF.Achtung: BINARY SEARCH bei einer nicht sortierten Tabelle liefert falsche Ergebnisse ohne Fehlermeldung!
5. READ TABLE mit TRANSPORTING NO FIELDS
" Nur prüfen, ob ein Kunde existiertREAD TABLE lt_customers TRANSPORTING NO FIELDS WITH KEY city = 'Berlin'.
IF sy-subrc = 0. WRITE: / 'Mindestens ein Kunde in Berlin (Index:', sy-tabix, ').'.ELSE. WRITE: / 'Kein Kunde in Berlin.'.ENDIF.6. READ TABLE mit mehreren Schlüsselfeldern
TYPES: BEGIN OF ty_order, customer_id TYPE i, order_id TYPE i, amount TYPE p DECIMALS 2, END OF ty_order.
DATA: lt_orders TYPE STANDARD TABLE OF ty_order WITH EMPTY KEY, ls_order TYPE ty_order.
lt_orders = VALUE #( ( customer_id = 1 order_id = 100 amount = '1500.00' ) ( customer_id = 1 order_id = 101 amount = '2300.50' ) ( customer_id = 2 order_id = 100 amount = '800.00' )).
" Bestellung für Kunde 1, Order 101 suchenREAD TABLE lt_orders INTO ls_order WITH KEY customer_id = 1 order_id = 101.
IF sy-subrc = 0. WRITE: / 'Betrag:', ls_order-amount.ENDIF.7. READ TABLE mit REFERENCE INTO
DATA: lr_customer TYPE REF TO ty_customer.
READ TABLE lt_customers REFERENCE INTO lr_customer WITH KEY id = 3.
IF sy-subrc = 0. " Zugriff über Dereferenzierung WRITE: / 'Name:', lr_customer->name. lr_customer->city = 'Köln'. " Ändert die Tabelle direktENDIF.Moderne Alternative: Tabellenausdrücke (ab ABAP 7.40)
Ab ABAP 7.40 können Tabellenausdrücke als kompakte Alternative verwendet werden:
Inline-Zugriff mit Tabellenausdruck
" Direkter Zugriff (löst Ausnahme aus, wenn nicht gefunden)TRY. DATA(ls_found) = lt_customers[ id = 2 ]. WRITE: / 'Gefunden:', ls_found-name. CATCH cx_sy_itab_line_not_found. WRITE: / 'Nicht gefunden.'.ENDTRY.
" Zugriff per IndexDATA(ls_first) = lt_customers[ 1 ].
" Mit OPTIONAL (gibt initiale Zeile zurück, wenn nicht gefunden)DATA(ls_safe) = VALUE #( lt_customers[ id = 99 ] OPTIONAL ).
" Mit DEFAULT (gibt Standardwert zurück, wenn nicht gefunden)DATA(ls_default) = VALUE #( lt_customers[ id = 99 ] DEFAULT VALUE #( id = 0 name = 'Unbekannt' ) ).Existenzprüfung mit line_exists()
IF line_exists( lt_customers[ id = 2 ] ). WRITE: / 'Kunde 2 existiert.'.ENDIF.
IF NOT line_exists( lt_customers[ city = 'Stuttgart' ] ). WRITE: / 'Kein Kunde in Stuttgart.'.ENDIF.Index ermitteln mit line_index()
DATA(lv_index) = line_index( lt_customers[ id = 2 ] ).
IF lv_index > 0. WRITE: / 'Kunde 2 ist an Position:', lv_index.ELSE. WRITE: / 'Nicht gefunden.'.ENDIF.READ TABLE vs. Tabellenausdruck
| Aspekt | READ TABLE | Tabellenausdruck |
|---|---|---|
| Syntax | Ausführlicher | Kompakt |
| Nicht gefunden | sy-subrc = 4 | Exception oder OPTIONAL |
| Index verfügbar | sy-tabix | line_index() |
| Performance | Identisch | Identisch |
| ASSIGNING | Ja | Ja (mit FIELD-SYMBOL) |
" Tabellenausdruck mit FeldsymbolASSIGN lt_customers[ id = 2 ] TO FIELD-SYMBOL(<fs_cust>).IF sy-subrc = 0. <fs_cust>-city = 'Dresden'.ENDIF.Abgrenzung zu LOOP AT
READ TABLE: Liest eine einzelne Zeile. Ideal für gezielte Zugriffe.LOOP AT: Durchläuft mehrere/alle Zeilen sequenziell.
" Eine bestimmte Zeile lesen → READ TABLEREAD TABLE lt_customers INTO ls_customer WITH KEY id = 2.
" Alle Zeilen mit bestimmtem Kriterium verarbeiten → LOOP ATLOOP AT lt_customers INTO ls_customer WHERE city = 'Berlin'. " Mehrere Zeilen verarbeitenENDLOOP.Performance-Tipps
-
Richtigen Tabellentyp wählen:
- Häufige Schlüsselzugriffe →
SORTED TABLEoderHASHED TABLE - Sequenzieller Zugriff →
STANDARD TABLE
- Häufige Schlüsselzugriffe →
-
BINARY SEARCH nur bei sortierten Tabellen: Verwenden Sie
SORTvor der binären Suche:" Falsch: BINARY SEARCH ohne SortierungREAD TABLE lt_unsorted INTO ls_wa WITH KEY field = value BINARY SEARCH. " Gefährlich!" Richtig: Erst sortierenSORT lt_data BY field.READ TABLE lt_data INTO ls_wa WITH KEY field = value BINARY SEARCH. -
Sekundärschlüssel nutzen:
DATA: lt_customers TYPE SORTED TABLE OF ty_customerWITH UNIQUE KEY idWITH NON-UNIQUE SORTED KEY by_city COMPONENTS city." Schneller Zugriff über SekundärschlüsselREAD TABLE lt_customers INTO ls_customerWITH KEY by_city COMPONENTS city = 'Berlin'. -
TRANSPORTING NO FIELDS für Existenzprüfungen: Wenn nur geprüft werden soll, ob eine Zeile existiert, ist
TRANSPORTING NO FIELDSeffizienter. -
Tabellenausdrücke mit line_exists(): Für reine Existenzprüfungen ist
line_exists()elegant und performant.
Wichtige Hinweise / Best Practice
- Prüfen Sie immer
sy-subrcnach einemREAD TABLE, bevor Sie auf die Ergebnisdaten zugreifen. - Verwenden Sie
ASSIGNINGfür bessere Performance und wenn Sie die Zeile ändern möchten. Alternativ können SieMODIFYverwenden. BINARY SEARCHnur verwenden, wenn die Tabelle garantiert sortiert ist (sieheSORT) – andernfalls sind die Ergebnisse unzuverlässig.- Für häufige Schlüsselzugriffe sollten Sie sortierte oder Hash-Tabellen in Betracht ziehen.
- Ab ABAP 7.40 sind Tabellenausdrücke oft die elegantere und kürzere Alternative.
- Bei Hash-Tabellen ist
sy-tabixnachREAD TABLEnicht definiert – verlassen Sie sich nicht darauf. READ TABLEist für interne Tabellen. Für Datenbanktabellen verwenden SieSELECT SINGLE.