[ABAP] IDoc: Strukturen der IDoc-Segmente in eine interne Tabelle lesen

* http://thinkdoforward.com/sap-idoc-tabellen-erfahrene-berater-kennen-diese-tabellen/

* Tabellen: EDIDC   – Kontrollsatz (IDoc)
*           EDIDS   – Statussatz (IDoc)
*           EDID4   – IDoc-Datensätze ab 4.0
*           EDISDEF - IDoc Entwicklung : IDoc Segmentdefinitionen
*           EDSAPPL - EDI: IDoc-Segment Anwendungsstruktur
*           EDIMSGT - Kurzbeschreibung der SAP Nachrichtentypen

TYPES: BEGIN OF ty_idoc_seg_entry,
         seg_name  TYPE string,
         comp_name TYPE string,
         value     TYPE string,
       END OF ty_idoc_seg_entry.

* IDoc-Nummer
PARAMETERS: p_idoc TYPE edidc-docnum DEFAULT '12345'.

START-OF-SELECTION.

* Lesen Segmentdaten des IDocs
  SELECT *
    INTO TABLE @DATA(it_int_edid)
    FROM edid4
    WHERE docnum EQ @p_idoc.

  IF sy-subrc = 0.
* Tabelle für aufbereitete Segmentdaten
    DATA: it_segment_data TYPE STANDARD TABLE OF ty_idoc_seg_entry WITH DEFAULT KEY.

* all. Feldsymbol für Umwandlung der Daten
    FIELD-SYMBOLS: <seg_data> TYPE any.

* Segmentdaten auslesen
    LOOP AT it_int_edid ASSIGNING FIELD-SYMBOL(<s>).
* Typecast für Umwandlung LCHR -> Type
      ASSIGN <s>-sdata TO <seg_data> CASTING TYPE (<s>-segnam).

* Typedescriptor zum Auslesen der einzelnen Datenfelder
      DATA(o_type) = cl_abap_typedescr=>describe_by_data( <seg_data> ).

      CASE o_type->kind.
* wenn Strukturtyp
        WHEN cl_abap_typedescr=>kind_struct.
          DATA(o_desc) = CAST cl_abap_structdescr( o_type ).

* Datenfelder der Struktur durchloopen
          LOOP AT o_desc->get_components( ) ASSIGNING FIELD-SYMBOL(<c>).
* Wert des Feldes auslesen
            ASSIGN COMPONENT <c>-name OF STRUCTURE <seg_data> TO FIELD-SYMBOL(<val>).
            IF <val> IS ASSIGNED.
* Zeile für Segment erstellen mit Segmentname, Komponenten-(Feld-)name, Wert
              APPEND VALUE #( seg_name  = <s>-segnam
                              comp_name = <c>-name
                              value     = <val>
                            ) TO it_segment_data.
            ENDIF.
          ENDLOOP.

        WHEN OTHERS.

      ENDCASE.
    ENDLOOP.

* Datenausgabe
    cl_demo_output=>display( it_segment_data ).
  ENDIF.

[ABAP] Vergleich von LOOPs mit Objektreferenzen und Feldsymbolen

* http://zevolving.com/2014/03/use-of-reference-variable-vs-workarea-vs-field-symbols/
DATA(it_p) = VALUE stringtab( ( |Udo| ) ( |Ede| ) ( |Ida| ) ).

* Code mit Referenz -> langsamer als ASSIGNING FIELD-SYMBOL
LOOP AT it_p REFERENCE INTO DATA(o_p).
* o_p dereferenzieren und Wert ausgeben
  WRITE: / o_p->*.
ENDLOOP.

* Code mit Feldsymbol -> schneller als REFERENCE INTO
LOOP AT it_p ASSIGNING FIELD-SYMBOL(<p>).
  WRITE: / <p>.
ENDLOOP.

[ABAP] Zugriff auf Elemente des Selektionsbildes (dirty assign)

SELECTION-SCREEN BEGIN OF LINE.
SELECTION-SCREEN COMMENT (8) lbl1 FOR FIELD p_name.
PARAMETERS: p_name TYPE string LOWER CASE.
SELECTION-SCREEN END OF LINE.

INITIALIZATION.
* "dirty assign" über Namen in Großbuchstaben
  ASSIGN ('LBL1') TO FIELD-SYMBOL(<l>).
  <l> = 'Eingabe:'.

* "dirty assign" über Namen in Großbuchstaben
  ASSIGN ('P_NAME') TO FIELD-SYMBOL(<p>).
  <p> = 'Test'.

START-OF-SELECTION.
  WRITE: / <l>, <p>.

[ABAP] RTTS / RTTI: Beispiele für dynamische Typ- und Objekterzeugung

* dynamisch einen Typ char40 erzeugen
DATA(o_type_char40) = cl_abap_elemdescr=>get_c( 40 ).
* dynamisch einen Typ string erzeugen
DATA(o_type_string) = cl_abap_elemdescr=>get_string( ).
* dynamisch einen Typ i erzeugen
DATA(o_type_int) = cl_abap_elemdescr=>get_i( ).
* dynamisch einen Typ decfloat34 erzeugen
DATA(o_type_d34) = cl_abap_elemdescr=>get_decfloat34( ).

* Referenz auf Objekt vom Typ char40 erzeugen
DATA: o_ref_char40 TYPE REF TO data.
CREATE DATA o_ref_char40 TYPE HANDLE o_type_char40.

* Referenz auf Objekt vom Typ string erzeugen
DATA: o_ref_string TYPE REF TO data.
CREATE DATA o_ref_string TYPE HANDLE o_type_string.

* Referenz auf Objekt vom Typ i erzeugen
DATA: o_ref_int TYPE REF TO data.
CREATE DATA o_ref_int TYPE HANDLE o_type_int.

* Referenz auf Objekt vom Typ i erzeugen
DATA: o_ref_d34 TYPE REF TO data.
CREATE DATA o_ref_d34 TYPE HANDLE o_type_d34.

* Referenz einem Feldsymbol zuweisen
ASSIGN o_ref_char40->* TO FIELD-SYMBOL(<char40>).
ASSIGN o_ref_string->* TO FIELD-SYMBOL(<string>).
ASSIGN o_ref_int->* TO FIELD-SYMBOL(<int>).
ASSIGN o_ref_d34->* TO FIELD-SYMBOL(<d34>).

* Wert auf Feldsymbol schreiben
<char40> = 'char40'.
<string> = 'string'.
<int> = 1.
<d34> = '3.1415926535'.

WRITE: / <char40>.
WRITE: / <string>.
WRITE: / <int>.
WRITE: / <d34>.

[ABAP] Arbeit mit Referenzen

einfache Wertänderung über Referenz

* int-Variable anlegen, Wert 1
DATA(lv_int) = 1.
* Referenz auf int
DATA(o_int) = REF #( lv_int ).

* Änderung auf Wert 2
lv_int = 2.

* Ausgabe Wert 2
WRITE: / o_int->*.

* Änderung auf 3
o_int->* = 3.

* Ausgabe Wert 3
WRITE: / lv_int.

mehrfache Wertänderung über Referenz

* int-Variable anlegen, Wert 1
DATA(lv_int) = 1.
* generische Referenz auf die int-Variable
DATA(o_int) = REF data( lv_int ).
* Variable auf Wert 2 ändern
lv_int = 2.

* Zwei Feldsymbole (<i1> und <i2>) mit der Referenz verknüpfen
ASSIGN o_int->* TO FIELD-SYMBOL(<i1>).
ASSIGN o_int->* TO FIELD-SYMBOL(<i2>).

* den Wert eines der Feldsymbole ändern
<i1> = 4.

* es ändern sich durch den Bezug sogleich alle anderen Feldsymbole und Variablen mit :)
WRITE: / lv_int.
WRITE: / <i1>.
WRITE: / <i2>.

generische Referenz auf interne Tabelle

* Stringtable aus DDIC (gefüllt)
DATA(it_stringtab) = VALUE stringtab( ( |Udo| )
                                      ( |Heinz| )
                                      ( |Klaus| ) ).

* generische Referenz auf die Stringtable
DATA(o_tab) = REF data( it_stringtab ).

* Feldsymbol explizit als generische Table definieren
FIELD-SYMBOLS: <tab> TYPE ANY TABLE.
* Feldsymbol auf die interne Tabelle mit der generischen Referenz verknüpfen
ASSIGN o_tab->* TO <tab>.

* Tabelleninhalt darstellen
LOOP AT <tab> ASSIGNING FIELD-SYMBOL(<l>).
  WRITE: / <l>.
ENDLOOP.

referentieller Zugriff auf eine interne Tabelle

* Typdeklaration
TYPES: ty_it_sflight TYPE STANDARD TABLE OF sflight WITH DEFAULT KEY.

* Tabelle anlegen
DATA(it_sflight) = VALUE ty_it_sflight( ( carrid = 'AA' connid = '0123' )
                                        ( carrid = 'LH' connid = '3210' ) ).

* generische Referenz auf die Table
DATA(o_tab) = REF data( it_sflight ).

* Feldsymbol explizit als generische Table definieren
FIELD-SYMBOLS: <tab> TYPE ty_it_sflight. " hier auch STANDARD TABLE möglich
* Feldsymbol auf die interne Tabelle mit der generischen Referenz verknüpfen
ASSIGN o_tab->* TO <tab>.

* wenn Zeilen in der Tabelle vorhanden
IF lines( <tab> ) > 0.
* erste Zeile holen und mit Feldsymbol verknüpfen
  ASSIGN <tab>[ 1 ] TO FIELD-SYMBOL(<row>).
* Struktur (Felder) der ersten Zeile ermitteln
  DATA(o_struct) = CAST cl_abap_structdescr( cl_abap_typedescr=>describe_by_data( <row> ) ).
* Anzahl Felder in der Struktur ermitteln
  DATA(lv_cnt) = lines( o_struct->get_components( ) ).

* Tabelleninhalt darstellen
  LOOP AT <tab> ASSIGNING <row>.

    DATA(lv_row) = ||.

* Felder durchgehen
    DO lv_cnt TIMES.
* Zellen einer zeile holen
      ASSIGN COMPONENT sy-index OF STRUCTURE <row> TO FIELD-SYMBOL(<cell>).
* Zellinhalt ausgeben
      IF sy-index = 0.
        lv_row = |{ <cell> }|.
      ELSE.
        lv_row = |{ lv_row } \| { <cell> }|.
      ENDIF.
    ENDDO.

    WRITE: / lv_row.
  ENDLOOP.

ENDIF.

[ABAP] Minimum/Maximum eines Datentyps ermitteln

* Variable deklarieren
DATA: lv_p TYPE p LENGTH 5 DECIMALS 2.

* Minimumwert ermitteln
DATA(lv_min) = cl_abap_exceptional_values=>get_min_value( lv_p ).
ASSIGN lv_min->* TO FIELD-SYMBOL(<min>).
IF <min> IS ASSIGNED.
  WRITE: / <min>.
ENDIF.

* Maximumwert ermitteln
DATA(lv_max) = cl_abap_exceptional_values=>get_max_value( lv_p ).
ASSIGN lv_max->* TO FIELD-SYMBOL(<max>).
IF <max> IS ASSIGNED.
  WRITE: / <max>.
ENDIF.

[ABAP] Eine Tabellenzeile einer internen Tabelle an ein Feldsymbol binden (Table Expressions)

DATA: itab TYPE STANDARD TABLE OF ...
FIELD-SYMBOLS: <fs1> TYPE ...

* Zeile mit Index 1 an Feldsymbol
ASSIGN itab[ 1 ] TO FIELD-SYMBOL(<fs1>).

FIELD-SYMBOLS: <fs2> TYPE ...

* Komponente 1 aus Zeile 2 an Feldsymbol
ASSIGN COMPONENT 1 OF STRUCTURE itab[ 2 ] TO FIELD-SYMBOL(<fs2>).

* Komponente 'NAME' aus Zeile 1 an Feldsymbol
ASSIGN COMPONENT 'NAME' OF STRUCTURE itab[ 1 ] TO FIELD-SYMBOL(<fs2>).

[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] Dynamische Tabelle anhand eines Tabellennamens erstellen, Daten ausgeben

DATA: table_name TYPE string VALUE 'spfli'. " Tabellenname
DATA: o_it TYPE REF TO data.                " Referenz auf Tabelle
DATA: o_row TYPE REF TO data.               " Referenz auf Tabellenzeile

FIELD-SYMBOLS: <fs_table> TYPE ANY TABLE.   " Feldsymbol für Arbeit mit Tabelle
FIELD-SYMBOLS: <fs_row> TYPE any.           " Feldsymbol für Arbeit mit Zeile

* dynamische Tabelle vom Typ table_name erzeugen
CREATE DATA o_it TYPE TABLE OF (table_name).
* Feldsymbol auf die dynamische Tabelle anlegen
ASSIGN o_it->* TO <fs_table>.

IF <fs_table> IS ASSIGNED.
* dynamische Workarea vom Typ der Tabellenzeile erzeugen
  CREATE DATA o_row LIKE LINE OF <fs_table>.
* Feldsymbol auf die Workarea anlegen
  ASSIGN o_row->* TO <fs_row>.

  IF <fs_row> IS ASSIGNED.
* Daten holen
    SELECT * FROM (table_name) INTO TABLE <fs_table>.

* Daten ausgeben
    DATA: go_struct TYPE REF TO cl_abap_structdescr.

* herausfinden, wieviele Spalten die Tabelle hat
    go_struct ?= cl_abap_typedescr=>describe_by_data( <fs_row> ).
    DATA(gt_comp) = go_struct->get_components( ).

* alle Datensätze der Tabelle durchgehen
    LOOP AT <fs_table> INTO <fs_row>.

* spaltenweise jeden Datensatz durchgehen
      LOOP AT gt_comp ASSIGNING FIELD-SYMBOL(<fs_col>).
* den Inhalt der Strukturkomponente (Zeile) ausgeben
        ASSIGN COMPONENT <fs_col>-name OF STRUCTURE <fs_row> TO FIELD-SYMBOL(<fs_cell>).

        IF <fs_cell> IS ASSIGNED.
          WRITE: <fs_cell>.
        ENDIF.
      ENDLOOP.

      NEW-LINE.

    ENDLOOP.
  ENDIF.
ENDIF.