[ABAP] Tabellentypen mit Beispielen

Übersicht interne Tabellen: Link

Beispieltyp

TYPES: BEGIN OF ty_long,
         posnr   TYPE posnr,
         matnr   TYPE matnr,
         vbeln   TYPE vbeln,
         flag_ok TYPE boolean,
       END OF ty_long.

STANDARD TABLE

* unsortiert, kann mit SORT sortiert werden
* Zugriff über Index und Schlüssel

DATA: it_st TYPE STANDARD TABLE OF ty_long WITH DEFAULT KEY.

SORTED TABLE

* nach definiertem Schlüssel sortiert
* Zugriff über Index und Schlüssel
* wenn Zugriff über Schlüssel
* schnell, da binäre Suche  

* Primary Key: posnr
* Secondary Key: flag
DATA: it_so TYPE SORTED TABLE OF ty_long WITH UNIQUE KEY posnr WITH NON-UNIQUE SORTED KEY flag COMPONENTS flag_ok.

* Primary Key: table_line
DATA: it_sorted TYPE SORTED TABLE OF string WITH UNIQUE KEY table_line.

HASHED TABLE

* Zugriff nur über eindeutigen Schlüssel, kein Index
* Zugriff nur über einen unique-Schlüssel -> jeder Schlüsselwert darf nur einmal vorkommen, sonst Exception
* schnell, wenn alle Schlüsselfelder einbezogen werden

* Primary Key: DEFAULT KEY
DATA: it_hadk TYPE HASHED TABLE OF ty_long WITH UNIQUE DEFAULT KEY.

* Primary Key: posnr
DATA: it_hauk TYPE HASHED TABLE OF ty_long WITH UNIQUE KEY posnr.

* Primary Key: DEFAULT KEY
* Secondary Key: flag 
DATA: it_hask TYPE HASHED TABLE OF ty_long WITH UNIQUE DEFAULT KEY WITH NON-UNIQUE SORTED KEY flag COMPONENTS flag_ok.

* Primary Key: posnr, matnr, vbeln
* Secondary Key: flag 
DATA: it_hauksk TYPE HASHED TABLE OF ty_long WITH UNIQUE KEY posnr matnr vbeln WITH NON-UNIQUE SORTED KEY flag COMPONENTS flag_ok.

[ABAP] Datensätze zwischen Tabellen mit unterschiedlichen Feldern und Datentypen kopieren

Beispiel 1 (APPEND CORRESPONDING)

* Typ für Tabelle mit kompletten Daten
TYPES: BEGIN OF ty_long,
         posnr   TYPE posnr,
         matnr   TYPE matnr,
         vbeln   TYPE vbeln,
         flag_ok TYPE boolean,
       END OF ty_long.

* Typ für Ausgabetabelle, Felder hier nur vom Datentyp string
TYPES: BEGIN OF ty_short,
         posnr TYPE string,
         matnr TYPE string,
         vbeln TYPE string,
       END OF ty_short.

DATA: it_long TYPE STANDARD TABLE OF ty_long WITH DEFAULT KEY.
DATA: it_short TYPE STANDARD TABLE OF ty_short WITH DEFAULT KEY.

* Beispieldaten
it_long = VALUE #( ( posnr = 1 matnr = '1111111111' vbeln = '3333333333' flag_ok = abap_true )
                   ( posnr = 2 matnr = '2222222222' vbeln = '4444444444' flag_ok = abap_false )
                   ( posnr = 3 matnr = '3333333333' vbeln = '5555555555' flag_ok = abap_true ) ).

* nur Datensätze kopieren, wo Flag gesetzt
LOOP AT it_long ASSIGNING FIELD-SYMBOL(<fs_l>) WHERE ( flag_ok = abap_true ).
* korrespondierende (namensgleiche) Felder des Datensatzes vom Typ ty_long an
* Tabelle mit Datensätzen vom Typ ty_short anhängen
  APPEND CORRESPONDING ty_short( <fs_l> ) TO it_short.
ENDLOOP.

* Testdaten ausgeben
LOOP AT it_short ASSIGNING FIELD-SYMBOL(<fs_s>).
  WRITE: / <fs_s>-posnr, <fs_s>-matnr, <fs_s>-vbeln.
ENDLOOP.

Beispiel 2 (CORRESPONDING, FILTER)

* Typ für Tabelle mit kompletten Daten
TYPES: BEGIN OF ty_long,
         posnr   TYPE posnr,
         matnr   TYPE matnr,
         vbeln   TYPE vbeln,
         flag_ok TYPE boolean,
       END OF ty_long.

* Typ für Ausgabetabelle, Felder hier nur vom Datentyp string
TYPES: BEGIN OF ty_short,
         posnr TYPE string,
         matnr TYPE string,
         vbeln TYPE string,
       END OF ty_short.

DATA: it_long TYPE SORTED TABLE OF ty_long WITH UNIQUE KEY posnr WITH NON-UNIQUE SORTED KEY flag COMPONENTS flag_ok.
DATA: it_short TYPE STANDARD TABLE OF ty_short WITH DEFAULT KEY.

* Beispieldaten
it_long = VALUE #( ( posnr = 1 matnr = '1111111111' vbeln = '3333333333' flag_ok = abap_true )
                   ( posnr = 2 matnr = '2222222222' vbeln = '4444444444' flag_ok = abap_false )
                   ( posnr = 3 matnr = '3333333333' vbeln = '5555555555' flag_ok = abap_true ) ).

* nur Datensätze kopieren, wo Flag gesetzt
* korrespondierende (namensgleiche) Felder des Datensatzes vom Typ ty_long in
* Tabelle mit Datensätzen vom Typ ty_short kopieren
it_short = CORRESPONDING #( FILTER #( it_long USING KEY flag WHERE flag_ok = abap_true ) ).

* Testdaten ausgeben
LOOP AT it_short ASSIGNING FIELD-SYMBOL(<fs_s>).
  WRITE: / <fs_s>-posnr, <fs_s>-matnr, <fs_s>-vbeln.
ENDLOOP.

[ABAP] Schleifenperformance durch Feldsymbole und binäre Suche verbessern

Variante 1 (langsam: keine Optimierung)

* Verkaufsbeleg: Kopfdaten
SELECT * FROM vbak INTO TABLE @DATA(it_vbak).
* Verkaufsbeleg: Positionsdaten
SELECT * FROM vbap INTO TABLE @DATA(it_vbap).

DATA(o_timer) = cl_abap_runtime=>create_hr_timer( ).
DATA(usec_start) = o_timer->get_runtime( ).

LOOP AT it_vbak ASSIGNING FIELD-SYMBOL(<k>).
  LOOP AT it_vbap ASSIGNING FIELD-SYMBOL(<p>) WHERE vbeln EQ <k>-vbeln.
    WRITE: / <p>-vbeln, <p>-matnr.
  ENDLOOP.
ENDLOOP.

DATA(usec_end) = o_timer->get_runtime( ).
DATA(usec) = CONV decfloat16( usec_end - usec_start ).
DATA(sec) = usec / 1000000.

WRITE: / 'Laufzeit:', sec, 's'.

Variante 2 (schnell: FIELD-SYMBOL, BINARY SEARCH)

* Verkaufsbeleg: Kopfdaten
SELECT * FROM vbak INTO TABLE @DATA(it_vbak).
* Verkaufsbeleg: Positionsdaten
SELECT * FROM vbap INTO TABLE @DATA(it_vbap).

* Tabelle muss aufsteigend sortiert sein, sonst stimmt der Rückgabeindex bei der binären Suche nicht
SORT: it_vbak BY vbeln.
SORT: it_vbap BY vbeln.

DATA(o_timer) = cl_abap_runtime=>create_hr_timer( ).
DATA(usec_start) = o_timer->get_runtime( ).

LOOP AT it_vbak ASSIGNING FIELD-SYMBOL(<k>).
* binäre Suche mit READ TABLE
* -> sollen stattdessen Table-Expressions verwendet werden, muss ein Sorted Key benutzt werden
  READ TABLE it_vbap TRANSPORTING NO FIELDS WITH KEY vbeln = <k>-vbeln BINARY SEARCH.
* gefundenen Index merken
  DATA(lv_index) = sy-tabix.

  IF sy-subrc = 0.
* Suche in der sortierten Tabelle ab Index lv_index
    LOOP AT it_vbap ASSIGNING FIELD-SYMBOL(<p>) FROM lv_index WHERE vbeln = <k>-vbeln.
      WRITE: / <p>-vbeln, <p>-matnr.
    ENDLOOP.
  ELSE.
    WRITE: / 'Fehler.'.
  ENDIF.
ENDLOOP.

DATA(usec_end) = o_timer->get_runtime( ).
DATA(usec) = CONV decfloat16( usec_end - usec_start ).
DATA(sec) = usec / 1000000.

WRITE: / 'Laufzeit:', sec, 's'.

Variante 3 (am schnellsten: FIELD-SYMBOLS, HASHED TABLES, Secondary Keys)

DATA: it_vbak TYPE HASHED TABLE OF vbak WITH UNIQUE KEY vbeln.
DATA: it_vbap TYPE HASHED TABLE OF vbap WITH UNIQUE KEY vbeln posnr                             " Primary Key
                                        WITH NON-UNIQUE SORTED KEY vbeln_sort COMPONENTS vbeln. " Secondary Key

* Verkaufsbeleg: Kopfdaten
SELECT * FROM vbak INTO TABLE it_vbak.
* Verkaufsbeleg: Positionsdaten
SELECT * FROM vbap INTO TABLE it_vbap.

DATA(o_timer) = cl_abap_runtime=>create_hr_timer( ).
DATA(usec_start) = o_timer->get_runtime( ).

LOOP AT it_vbak ASSIGNING FIELD-SYMBOL(<k>).
* Nested Loop über Secondary Key vbeln_sort
* BINARY SEARCH wird durch die Verwendung des Secondary Keys implizit ausgeführt
  LOOP AT it_vbap ASSIGNING FIELD-SYMBOL(<p>) USING KEY vbeln_sort WHERE vbeln = <k>-vbeln.
    WRITE: / <p>-vbeln, <p>-matnr.
  ENDLOOP.
ENDLOOP.

DATA(usec_end) = o_timer->get_runtime( ).
DATA(usec) = CONV decfloat16( usec_end - usec_start ).
DATA(sec) = usec / 1000000.

WRITE: / 'Laufzeit:', sec, 's'.

Links

[ABAP] Zugriff auf interne Tabellen mit Table expressions

* Zeile (Struct) per Index
TRY.
   DATA(wa) = itab[ idx ].
   ...
   CATCH cx_sy_itab_line_not_found.
   ...
ENDTRY.

* Zelle per Index
TRY.
   DATA(var) = itab[ 1 ]-colname.
   ...
   CATCH cx_sy_itab_line_not_found.
   ...
ENDTRY.

* Suche mit Keys
* Suche mit TE ist Case-Sensitiv
* es wird immer nur die erste gefundene Zeile der Ergebnismenge geliefert

TRY.
   DATA(wa) = itab[ colname = 'abc' ].
   DATA(wa2) = itab[ colname = 'ABC' colname2 = '123' ].
* Zugriff per Secondary Key mit Komponenten
   DATA(wa3) = itab[ KEY sec_key COMPONENTS colname = '123' ].
   ...
   CATCH cx_sy_itab_line_not_found.
   ...
ENDTRY.

* Prüfen, ob Eintrag existiert
IF line_exists( itab[ colname = 'abc' ] ).
  ...
ENDIF.

* Arbeit mit Feldsymbolen um Faktor 2-3 schneller
DATA: itab TYPE ...
FIELD-SYMBOLS: <fs_data> TYPE ...

DO 100000 TIMES.
  ASSIGN itab[ col = sy-index ] TO <fs_data>.
  <ls_data>...
ENDDO.

Weiterführende Infos: Link, Link und Link

[ABAP] Daten von interner Tabelle lesen (Index, Key, Feldsymbol)

Typen & Daten

* Zeilentyp der internen Tabelle
TYPES : BEGIN OF ty_s_persons,
          pernr TYPE i,
          name  TYPE string,
          age   TYPE i,
        END OF ty_s_persons.

* Typ: Interne Tabelle mit Primärschlüssel pernr und Sekundärschlüssel persons
TYPES: ty_it_persons TYPE STANDARD TABLE OF ty_s_persons WITH KEY pernr
                                                         WITH NON-UNIQUE SORTED KEY persons COMPONENTS name.

* Daten
DATA(it_persons) = VALUE ty_it_persons(
                                        ( pernr = 1 name = |Udo|    age = 20 )
                                        ( pernr = 2 name = |Heinz|  age = 30 )
                                        ( pernr = 3 name = |Jochen| age = 40 )
                                        ( pernr = 4 name = |Ede|    age = 50 )
                                        ( pernr = 5 name = |Ina|    age = 60 )
                                        ( pernr = 6 name = |Erika|  age = 70 )
                                        ( pernr = 7 name = |Erna|   age = 80 )
                                      ).

Datensatz mit Index 1 auslesen

* table expressions
IF line_exists( it_persons[ 1 ] ).
* Datenstruktur
  DATA(lv_per1) = it_persons[ 1 ].
  WRITE: / lv_per1-pernr, lv_per1-name, lv_per1-age.

* Feldsymbol
  ASSIGN it_persons[ 1 ] TO FIELD-SYMBOL(<p1>).
  IF <p1> IS ASSIGNED.
    WRITE: / <p1>-pernr, <p1>-name, <p1>-age.
  ENDIF.
ENDIF.

* READ TABLE
* Datenstruktur
READ TABLE it_persons INDEX 1 INTO DATA(lv_per2).
IF sy-subrc = 0.
  WRITE: / lv_per2-pernr, lv_per2-name, lv_per2-age.
ENDIF.
* Feldsymbol
READ TABLE it_persons INDEX 1 ASSIGNING FIELD-SYMBOL(<p2>).
IF sy-subrc = 0 AND <p2> IS ASSIGNED.
  WRITE: / <p2>-pernr, <p2>-name, <p2>-age.
ENDIF.

Datensatz mit Primärschlüssel auslesen

* table expressions
IF line_exists( it_persons[ pernr = 2 ] ).
* Datenstruktur
  DATA(lv_per3) = it_persons[ pernr = 2 ].
  WRITE: / lv_per3-pernr, lv_per3-name, lv_per3-age.

* Feldsymbol
  ASSIGN it_persons[ pernr = 2 ] TO FIELD-SYMBOL(<p3>).
  IF <p3> IS ASSIGNED.
    WRITE: / <p3>-pernr, <p3>-name, <p3>-age.
  ENDIF.
ENDIF.

* READ TABLE
* Datenstruktur
READ TABLE it_persons WITH TABLE KEY pernr = 2 INTO DATA(lv_per4).
IF sy-subrc = 0.
  WRITE: / lv_per4-pernr, lv_per4-name, lv_per4-age.
ENDIF.
* Feldsymbol
READ TABLE it_persons WITH TABLE KEY pernr = 2 ASSIGNING FIELD-SYMBOL(<p4>).
IF sy-subrc = 0 AND <p4> IS ASSIGNED.
  WRITE: / <p4>-pernr, <p4>-name, <p4>-age.
ENDIF.

Datensatz mit Sekundärschlüssel auslesen

* table expressions
IF line_exists( it_persons[ KEY persons COMPONENTS name = 'Ina' ] ).
* Datenstruktur
  DATA(lv_per5) = it_persons[ KEY persons COMPONENTS name = 'Ina' ].
  WRITE: / lv_per5-pernr, lv_per5-name, lv_per5-age.

* Feldsymbol
  ASSIGN it_persons[ KEY persons COMPONENTS name = 'Ina' ] TO FIELD-SYMBOL(<p5>).
  IF <p5> IS ASSIGNED.
    WRITE: / <p5>-pernr, <p5>-name, <p5>-age.
  ENDIF.
ENDIF.

* READ TABLE
* Datenstruktur
READ TABLE it_persons WITH KEY persons COMPONENTS name = 'Ina' INTO DATA(lv_per6).
IF sy-subrc = 0.
  WRITE: / lv_per6-pernr, lv_per6-name, lv_per6-age.
ENDIF.
* Feldsymbol
READ TABLE it_persons WITH KEY persons COMPONENTS name = 'Ina' ASSIGNING FIELD-SYMBOL(<p6>).
IF sy-subrc = 0 AND <p6> IS ASSIGNED.
  WRITE: / <p6>-pernr, <p6>-name, <p6>-age.
ENDIF.