[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.

[ABAP] dynamische Tabelle zur Laufzeit aus einem Feldkatalog erstellen und in SALV-Table anzeigen

DATA : it_fcat TYPE lvc_t_fcat.

CALL FUNCTION 'LVC_FIELDCATALOG_MERGE'
  EXPORTING
    i_structure_name = 'SPFLI'  " Dictionary-Struktur
  CHANGING
    ct_fieldcat      = it_fcat. " Feldkatalog

DATA: o_tab TYPE REF TO data.
* dynamische Tabelle aus dem Feldkatalog erstellen
cl_alv_table_create=>create_dynamic_table( EXPORTING
                                             it_fieldcatalog = it_fcat
                                           IMPORTING
                                             ep_table        = o_tab ).

* dynamische Tabelle auf Feldsymbol abbilden
FIELD-SYMBOLS: <tab> TYPE ANY TABLE.
ASSIGN o_tab->* TO <tab>.

* Daten holen
SELECT * FROM spfli INTO TABLE <tab> UP TO 10 ROWS.

* Daten anzeigen
DATA: o_alv TYPE REF TO cl_salv_table.
TRY.
    cl_salv_table=>factory( IMPORTING
                              r_salv_table = o_alv
                            CHANGING
                              t_table      = <tab> ).

    o_alv->display( ).

  CATCH cx_root.
ENDTRY.

Links

[ABAP] Interne Tabelle nach XML exportieren

DATA: ti_t100 TYPE STANDARD TABLE OF t100.
DATA: lv_xml TYPE string.

* Daten abfragen
SELECT * FROM t100 INTO TABLE ti_t100 UP TO 10 ROWS.

* interne Tabelle in XML-String wandeln
CALL TRANSFORMATION id SOURCE data_node = ti_t100 RESULT XML lv_xml.

* Versionsinfo wegschneiden, damit in Excel die Spalte "Version" nicht erscheint
REPLACE FIRST OCCURRENCE OF | version="1.0">| IN ls_xml WITH '>'.

* XML-String in XML-Document wandeln
DATA(lo_xml_doc) = NEW cl_xml_document( ).
lo_xml_doc->parse_string( lv_xml ).

* XML-Document als Datei speichern
lo_xml_doc->export_to_file( 'c:\temp\test.xml' ).

WRITE: / |XML-Datei exportiert.|.

[ABAP] JSON (trex) -> itab

DATA: json type string VALUE '[{name: "Horst", title: "Herr", age: "30 "}, {name: "Jutta", title: "Frau", age: "35 "}, {name: "Ingo", title: "Herr", age: "31 "}]'.

TYPES: BEGIN OF s_person,
         name  TYPE string,
         title TYPE string,
         age   TYPE i,
       END OF s_person.

TYPES: t_person TYPE STANDARD TABLE OF s_person WITH DEFAULT KEY.

DATA(it_persons) = VALUE t_person( ).

* JSON (trex) -> ABAP (iTab)
DATA(o_trex) = NEW cl_trex_json_deserializer( ).
o_trex->deserialize( EXPORTING json = json
                     IMPORTING abap = it_persons ).

IF lines( it_persons ) > 0.
  WRITE: / it_persons[ 1 ]-name.
ENDIF.

[ABAP] Interne Tabelle mit NEW-Operator erstellen / Zugriff über Feldsymbole und Table Expressions

* Zeile
TYPES: BEGIN OF ty_data,
         kunnr TYPE i,
         name TYPE string,
         ort TYPE string,
       END   OF ty_data.
* Tabellentyp
TYPES: it_itab TYPE STANDARD TABLE OF ty_data WITH DEFAULT KEY.
* Feldsymbol für Zugriff
FIELD-SYMBOLS: <lt_text> TYPE it_itab.

* neue interne Tabelle mit Inhalt erstellen
DATA(dref) = NEW it_itab( ( kunnr = '123' name = 'ABCD' ort = 'LV' )
                          ( kunnr = '456' name = 'XYZ'  ort = 'LA' ) ).

* Zuweisung Feldsymbol
ASSIGN dref->* TO <lt_text>.

* Zugriff auf Inhalt der internen Tabelle über Feldsymbol und Table Expression
WRITE: / <lt_text>[ 1 ]-ort.

[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] Zwischenablage (Clipboard) verwenden

DATA: itab TYPE STANDARD TABLE OF sflight.
DATA: i_rc TYPE i.

...

* Export-Tabellen dürfen nicht generischen Typs und keine String-Tables sein
cl_gui_frontend_services=>clipboard_export( EXPORTING
                                              no_auth_check        = abap_true
                                            IMPORTING
                                              data                 = itab
                                            CHANGING
                                              rc                   = lv_rc
                                            EXCEPTIONS
                                              cntl_error           = 1
                                              error_no_gui         = 2
                                              not_supported_by_gui = 3
                                              OTHERS               = 4 ).

IF sy-subrc = 0.
  ...
ENDIF.

[ABAP] CSV-Datei in interne Table einlesen

Variante 1 (cl_gui_frontend_services, freier Separator)

* Beispiel für die CSV-Eingabedaten:
* Mandant;Fluggesellschaft;Flugnummer;Land;Abflugstadt;Startflugh.;Land;Ankunftstadt;Zielflugh.;Flugdauer;Abflug;Ankunftszeit;Entfernung;Entfernung in;Charter;n Tag(e) später;
* 900;AA;0017;US;NEW YORK;JFK;US;SAN FRANCISCO;SFO;  6:01;11:00:00;14:01:00;2572;MI;;0;
* 900;AA;0064;US;SAN FRANCISCO;SFO;US;NEW YORK;JFK;  5:21;09:00:00;17:21:00;2572;MI;;0;

* Ausgabestruktur (Spalten) für die eingelesenen und gesplitteten CSV-Daten
* der Einfachheit halber hier alles erstmal als Strings abbilden
TYPES : BEGIN OF ty_s_csv,
          mandant          TYPE string,
          fluggesellschaft TYPE string,
          flugnummer       TYPE string,
          land_ab          TYPE string,
          abflugstadt	   TYPE string,
          startflughafen   TYPE string,
          land_an          TYPE string,
          ankunftstadt     TYPE string,
          zielflughafen    TYPE string,
          flugdauer        TYPE string,
          abflug           TYPE string,
          ankunftszeit     TYPE string,
          entfernung       TYPE string,
          einheit          TYPE string,
          charter          TYPE string,
          tage             TYPE string,
        END OF ty_s_csv.

* Tabellentypen
TYPES: ty_it_csv TYPE STANDARD TABLE OF ty_s_csv WITH DEFAULT KEY.

* Überschriften vorhanden
PARAMETERS: p_head AS CHECKBOX DEFAULT 'X'.
* Separator / Trennzeichen
PARAMETERS: p_sep TYPE char1 DEFAULT ';'.

TRY.
    DATA: lv_rc TYPE i.
    DATA: it_files TYPE filetable.
    DATA: lv_action TYPE i.

* FileOpen-Dialog aufrufen
    cl_gui_frontend_services=>file_open_dialog( EXPORTING
                                                  file_filter    = |csv (*.csv)\|*.csv\|{ cl_gui_frontend_services=>filetype_all }|
                                                  multiselection = abap_false
                                                CHANGING
                                                  file_table     = it_files
                                                  rc             = lv_rc
                                                  user_action    = lv_action ).

    IF lv_action = cl_gui_frontend_services=>action_ok.
* wenn mind. eine Dateie ausgewählt worden ist
      IF lines( it_files ) = 1.

* Tabelle für Einlesedaten
        DATA(it_strings) = VALUE string_table( ).

* eingelesene Datei zeilenweise als Stringdaten einlesen
        cl_gui_frontend_services=>gui_upload( EXPORTING
                                                filename = CONV #( it_files[ 1 ]-filename )
                                                filetype = 'ASC'             " Dateityp BIN, ASC, DAT
                                              CHANGING
                                                data_tab = it_strings ).           " Übergabetabelle für Datei-Inhalt

        cl_demo_output=>write_data( it_strings ).

* Wenn mit Header, dann ab Zeile 2, sonst gleich ab Zeile 1
        DATA(lv_startzeile) = COND i( WHEN p_head = abap_true THEN 2 ELSE 1 ).

* Je nach Vorhandensein des Headers prüfen, ob genug Zeilen in der Tabelle
        IF ( lines( it_strings ) > lv_startzeile - 1 ).
* Ausgabetabelle mit ausgesplitteten CSV-Daten
          DATA(it_csv) = VALUE ty_it_csv( ).

* Eingelesene Strings durchlaufen, Start bei Zeile 1 (mit Header) oder 2 (mit Header)
          LOOP AT it_strings ASSIGNING FIELD-SYMBOL(<z>) FROM lv_startzeile.
* neue Ausgabezeile
            DATA(lv_csv_line) = VALUE ty_s_csv( ).

* String anhand des Separators aufsplitten
            SPLIT <z> AT p_sep INTO TABLE DATA(it_columns).

* Wenn anzahl der Splitelemente == Anzahl Felder in der CSV-Struktur
            IF lines( it_columns ) = 16.
* gesplittete Daten in die neue CSV-Zeile übernehmen
              lv_csv_line-mandant = it_columns[ 1 ].
              lv_csv_line-fluggesellschaft = it_columns[ 2 ].
              lv_csv_line-flugnummer = it_columns[ 3 ].
              lv_csv_line-land_ab = it_columns[ 4 ].
              lv_csv_line-abflugstadt = it_columns[ 5 ].
              lv_csv_line-startflughafen = it_columns[ 6 ].
              lv_csv_line-land_an = it_columns[ 7 ].
              lv_csv_line-ankunftstadt = it_columns[ 8 ].
              lv_csv_line-zielflughafen = it_columns[ 9 ].
              lv_csv_line-flugdauer = it_columns[ 10 ].
              lv_csv_line-abflug = it_columns[ 11 ].
              lv_csv_line-ankunftszeit = it_columns[ 12 ].
              lv_csv_line-entfernung = it_columns[ 13 ].
              lv_csv_line-einheit = it_columns[ 14 ].
              lv_csv_line-charter = it_columns[ 15 ].
              lv_csv_line-tage = it_columns[ 16 ].
            ENDIF.

* neue CSV-Zeile an Ausgabetabelle anfügen
            APPEND lv_csv_line TO it_csv.
          ENDLOOP.

          cl_demo_output=>write_data( it_csv ).

* HTML-Code vom Demo-Output holen
          DATA(lv_html) = cl_demo_output=>get( ).
* Daten im Inline-Browser im SAP-Fenster anzeigen
          cl_abap_browser=>show_html( EXPORTING
                                        title        = 'Daten aus CSV'
                                        html_string  = lv_html
                                        container    = cl_gui_container=>default_screen ).

* cl_gui_container=>default_screen erzwingen
          WRITE: space.
        ENDIF.
      ENDIF.
    ENDIF.
  CATCH cx_root INTO DATA(e_text).
    MESSAGE e_text->get_text( ) TYPE 'I'.
ENDTRY.

Variante 2 (cl_gui_frontend_services, freier Separator, dynamisches Einlesen von CSV-Daten)

* Überschriften vorhanden
PARAMETERS: p_head AS CHECKBOX DEFAULT 'X'.
* Separator / Trennzeichen
PARAMETERS: p_sep TYPE char1 DEFAULT ';'.

TRY.
    DATA: lv_rc TYPE i.
    DATA: it_files TYPE filetable.
    DATA: lv_action TYPE i.

* FileOpen-Dialog aufrufen
    cl_gui_frontend_services=>file_open_dialog( EXPORTING
                                                  file_filter    = |csv (*.csv)\|*.csv\|{ cl_gui_frontend_services=>filetype_all }|
                                                  multiselection = abap_false
                                                CHANGING
                                                  file_table     = it_files
                                                  rc             = lv_rc
                                                  user_action    = lv_action ).

    IF lv_action = cl_gui_frontend_services=>action_ok.
* wenn mind. eine Dateie ausgewählt worden ist
      IF lines( it_files ) = 1.

* Tabelle für Einlesedaten
        DATA(it_strings) = VALUE string_table( ).

* eingelesene Datei zeilenweise als Stringdaten einlesen
        cl_gui_frontend_services=>gui_upload( EXPORTING
                                                filename = CONV #( it_files[ 1 ]-filename )
                                                filetype = 'ASC'             " Dateityp BIN, ASC, DAT
                                              CHANGING
                                                data_tab = it_strings ).     " Übergabetabelle für Datei-Inhalt

        cl_demo_output=>write_data( it_strings ).

        DATA(it_errors) = VALUE string_table( ).

* Wenn mit Header, dann ab Zeile 2, sonst gleich ab Zeile 1
        DATA(lv_startzeile) = COND i( WHEN p_head = abap_true THEN 2 ELSE 1 ).

* Je nach Vorhandensein des Headers prüfen, ob genug Zeilen (für Erstellung des Headers) in der Tabelle
        IF ( lines( it_strings ) > lv_startzeile - 1 ).

* 1. verfügbaren String aus der eingelesenen Tabelle anhand des Separators aufsplitten
          SPLIT it_strings[ 1 ] AT p_sep INTO TABLE DATA(it_cnt_col).

* Komponenten (Spalten) der Tabelle
          DATA(it_components) = VALUE cl_abap_structdescr=>component_table( ).

* Komponententabelle füllen
          LOOP AT it_cnt_col ASSIGNING FIELD-SYMBOL(<c>).
* Standard-Spaltenbezeichner vorbelegen (COL1...COLn)
            DATA(lv_name) = |COL{ sy-tabix }|.

* Wenn Header vorhanden, dann Header übernehmen
            IF p_head = abap_true.
              lv_name = <c>.
* alle Vorkommen, die nicht [a-zA-Z0-9_] entsprechen, durch '_' ersetzen
              REPLACE ALL OCCURRENCES OF REGEX '([^\w]|[äöüÄÖÜß])+' IN lv_name WITH '_'.
            ENDIF.

* Spalte vom Typ String zur Komponententabelle hinzufügen
            APPEND VALUE #( name = lv_name
                            type = cl_abap_elemdescr=>get_string( )
                          ) TO it_components.
          ENDLOOP.

* Strukturdeskriptor für Komponententabelle
          DATA(o_struct_desc) = cl_abap_structdescr=>create( it_components ).

* Tabellendeskriptor erzeugen
          DATA(o_table_desc) = cl_abap_tabledescr=>create(
                                                           p_line_type  = o_struct_desc                          " Spalten
                                                           p_table_kind = cl_abap_tabledescr=>tablekind_std      " Tabellentyp STANDARD TABLE
                                                           p_unique     = abap_false                             " NON-UNIQUE KEY
                                                           p_key_kind   = cl_abap_tabledescr=>keydefkind_default " Benutzerdefinierter Schlüssel
                                                         ).

* Tabellenobjekt anhand des Tabellendeskriptors erstellen
          DATA: o_table TYPE REF TO data.
          CREATE DATA o_table TYPE HANDLE o_table_desc.

* Feldsymbol auf das Tabellenobjekt
          FIELD-SYMBOLS <csv_table> TYPE STANDARD TABLE.
          ASSIGN o_table->* TO <csv_table>.

* Eingelesene Strings durchlaufen, Start bei Zeile 1 (ohne Header) oder 2 (mit Header)
          LOOP AT it_strings ASSIGNING FIELD-SYMBOL(<z>) FROM lv_startzeile.
* neue Ausgabezeile anfügen
            APPEND INITIAL LINE TO <csv_table>.
* neue Ausgabezeile holen
            DATA(lv_lc) = lines( <csv_table> ).
            ASSIGN <csv_table>[ lv_lc ] TO FIELD-SYMBOL(<row>).

* String anhand des Separators aufsplitten
            SPLIT <z> AT p_sep INTO TABLE DATA(it_column_data).

* Wenn anzahl der Splitelemente == Anzahl Felder in der CSV-Struktur
            IF lines( it_column_data ) = lines( it_components ).
* gesplittete Daten in die neue CSV-Zeile übernehmen
              LOOP AT it_components ASSIGNING FIELD-SYMBOL(<comp>).
* n-te Spalte <col> der akt. Tabellenzeile <row> ermitteln
                ASSIGN COMPONENT sy-tabix OF STRUCTURE <row> TO FIELD-SYMBOL(<col>).
* den n-ten gesplitteten Wert der n-ten Spalte <col> der akt. Tabellenzeile <row> zuordnen
                <col> = it_column_data[ sy-tabix ].
              ENDLOOP.
            ELSE.
* Wenn abweichende Spaltenanzahl vom Header
              APPEND |Zeile { sy-tabix }: Spaltenanzahl ({ lines( it_column_data ) }) weicht vom Header ({ lines( it_components ) }) ab.| TO it_errors.
            ENDIF.

          ENDLOOP.

          cl_demo_output=>write_data( it_errors ).

          cl_demo_output=>write_data( <csv_table> ).

* HTML-Code vom Demo-Output holen
          DATA(lv_html) = cl_demo_output=>get( ).
* Daten im Inline-Browser im SAP-Fenster anzeigen
          cl_abap_browser=>show_html( EXPORTING
                                        title        = 'Daten aus CSV'
                                        html_string  = lv_html
                                        container    = cl_gui_container=>default_screen ).

* cl_gui_container=>default_screen erzwingen
          WRITE: space.
        ENDIF.
      ENDIF.
    ENDIF.
  CATCH cx_root INTO DATA(e_text).
    MESSAGE e_text->get_text( ) TYPE 'I'.
ENDTRY.

Variante 3 (cl_gui_frontend_services, TAB-Zeichen als Separator)

* CSV-Datei mit drei Spalten
TYPES: BEGIN OF ty_s_type,
         col1 TYPE string,
         col2 TYPE string,
         col3 TYPE string,
       END OF ty_s_type.

TYPES: ty_it_csv TYPE STANDARD TABLE OF ty_s_type WITH DEFAULT KEY.

DATA: it_csv TYPE ty_it_csv.

TRY.
  * Setzt voraus, dass die CSV-Daten TAB-getrennt sind!
    cl_gui_frontend_services=>gui_upload( EXPORTING
                                            filename            = 'c:\temp\test.csv' " Eingabedatei
                                            filetype            = 'ASC'              " Dateityp BIN, ASC, DAT
                                            has_field_separator = abap_true          " Spalten durch TAB getrennt bei ASCII Upload?
                                          CHANGING
                                            data_tab            = it_csv ).          " Übergabetabelle für Datei-Inhalt

    cl_demo_output=>write_data( it_csv ).

  CATCH cx_root INTO DATA(e_text).
    MESSAGE e_text->get_text( ) TYPE 'I'.
ENDTRY.

Variante 4 (Funktionbaustein, obsolet)

* CSV-Datei mit drei Spalten
TYPES: BEGIN OF ty_s_type,
         col1 TYPE string,
         col2 TYPE string,
         col3 TYPE string,
       END OF ty_s_type.

TYPES: ty_it_csv TYPE STANDARD TABLE OF ty_s_type WITH DEFAULT KEY.

DATA: it_csv TYPE ty_it_csv.

* Funktion ruft eigenen File-Open-Dialog auf
* FuBa UPLOAD ist obsolet
CALL FUNCTION 'UPLOAD'
  EXPORTING
    filename                = 'c:\temp\data.txt' " Dateinamen vorbelegen
    filetype                = 'DAT'              " Eingabedatei-Typ: Datentabelle ASCII mit Spaltentabulator
  TABLES
    data_tab                = it_csv
  EXCEPTIONS
    conversion_error        = 1
    file_open_error         = 2
    file_read_error         = 3
    invalid_table_width     = 4
    invalid_type            = 5
    no_batch                = 6
    unknown_error           = 7
    gui_refuse_filetransfer = 8
    OTHERS                  = 9.
    
IF sy-subrc <> 0.
  MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.