[ABAP] Daten effizient zu internen Tabellen hinzufügen

Variante 1 (HASHED TABLE)

TYPES: BEGIN OF ty_msgnr,
         msgnr TYPE t100-msgnr,
       END OF ty_msgnr.

DATA: it_t100 TYPE HASHED TABLE OF t100 WITH UNIQUE KEY sprsl arbgb msgnr.

SELECT * FROM t100
  INTO TABLE @it_t100
  UP TO 100000 ROWS.

DATA: it_msgnr TYPE HASHED TABLE OF ty_msgnr WITH UNIQUE KEY msgnr.

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

LOOP AT it_t100 ASSIGNING FIELD-SYMBOL(<s>).
* jedes Element auf Vorhandensein Prüfen und ggf. zur Liste hinzufügen
  IF NOT line_exists( it_msgnr[ msgnr = <s>-msgnr ] ).
    INSERT VALUE ty_msgnr( msgnr = <s>-msgnr ) INTO TABLE it_msgnr.
  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 2 (GROUP BY)

TYPES: BEGIN OF ty_msgnr,
         msgnr TYPE t100-msgnr,
       END OF ty_msgnr.

*DATA: it_t100 TYPE HASHED TABLE OF t100 WITH UNIQUE KEY sprsl arbgb msgnr.
DATA: it_t100 TYPE STANDARD TABLE OF t100 WITH DEFAULT KEY.

SELECT * FROM t100
  INTO TABLE @it_t100
  UP TO 100000 ROWS.

DATA: it_msgnr TYPE STANDARD TABLE OF ty_msgnr WITH DEFAULT KEY.

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

LOOP AT it_t100 ASSIGNING FIELD-SYMBOL(<s>) GROUP BY <s>-msgnr ASCENDING.
* jedes Element auf Vorhandensein Prüfen und ggf. zur Liste hinzufügen
  APPEND VALUE ty_msgnr( msgnr = <s>-msgnr ) TO it_msgnr.
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: COLLECT)

TYPES: BEGIN OF ty_msgnr,
         msgnr TYPE t100-msgnr,
       END OF ty_msgnr.

* Messages lesen
SELECT * FROM t100
  INTO TABLE @DATA(it_t100)
  UP TO 100000 ROWS.

DATA: it_msgnr TYPE STANDARD TABLE OF ty_msgnr WITH DEFAULT KEY.

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

LOOP AT it_t100 ASSIGNING FIELD-SYMBOL(<s>).
* jedes Element auf Vorhandensein Prüfen und ggf. zur Liste hinzufügen
* COLLECT verwendet intern HASHED TABLES
  COLLECT VALUE ty_msgnr( msgnr = <s>-msgnr ) INTO it_msgnr.
ENDLOOP.

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

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

[ABAP] Konvertierung HTML-String nach HTML-itab

* Konvertierungsklasse HTML-String nach HTML-itab
CLASS lcl_html_str_to_itab DEFINITION FINAL.
  PUBLIC SECTION.

* Zeilenlänge für HTML-itab
    CONSTANTS: co_html_length TYPE i VALUE 1024.
* HTML-itab
    TYPES: ty_html_line TYPE c LENGTH co_html_length.
    TYPES: ty_it_html TYPE STANDARD TABLE OF ty_html_line WITH DEFAULT KEY.

    CLASS-METHODS:
      convert
        IMPORTING
                  i_html_str        TYPE string
        RETURNING VALUE(rv_it_html) TYPE ty_it_html.

ENDCLASS.

CLASS lcl_html_str_to_itab IMPLEMENTATION.
**********************************************************************
* Konvertiert HTML-String nach HTML-itab
**********************************************************************
* i_html_str -> HTML-String
* rv_it_html <- HTML-itab
**********************************************************************
  METHOD convert.

    DATA(lv_right) = i_html_str.

    WHILE strlen( lv_right ) >= co_html_length.
* linker Teil
      DATA(lv_left) = substring( val = lv_right off = 0 len = co_html_length ).
      APPEND lv_left TO rv_it_html.

* Rest
      lv_right = substring( val = lv_right off = co_html_length len = strlen( lv_right ) - co_html_length ).
    ENDWHILE.

* Rest anfügen
    IF strlen( lv_right ) > 0.
      APPEND lv_right TO rv_it_html.
    ENDIF.

  ENDMETHOD.

ENDCLASS.

START-OF-SELECTION.
* Daten holen
  SELECT * FROM tnapr INTO TABLE @DATA(it_tnapr).

* HTML-Daten aus itab generieren
  DATA(lv_html) = cl_demo_output=>get( it_tnapr ).

* HTML-String nach HTML itab konvertieren
  DATA(it_html) = lcl_html_str_to_itab=>convert( lv_html  ).

* HTML-Viewer
  DATA(o_hv) = NEW cl_gui_html_viewer( parent = cl_gui_container=>default_screen ).
* URL holen
  DATA: lv_url type swk_url.

  o_hv->load_data( IMPORTING
                     assigned_url = lv_url
                   CHANGING
                     data_table   = it_html ).

* Daten anzeigen
  o_hv->show_url( url      = lv_url
                  in_place = abap_true ). " im SAP-Fenster (abap_true) oder im Externen Browser (abap_false) anzeigen

* cl_gui_container=>default_screen erzwingen
  WRITE: space.

[ABAP] PDF im Browserfenster anzeigen

TRY.
    DATA: it_sel_filetab TYPE filetable.
    DATA: ret_code TYPE i.
    DATA: lv_action TYPE i.

* FileOpen-Dialog für Dateiauswahl anzeigen
    cl_gui_frontend_services=>file_open_dialog( EXPORTING
                                                  window_title            = 'PDF-Datei öffnen'
                                                  multiselection          = abap_false
                                                CHANGING
                                                  file_table              = it_sel_filetab
                                                  rc                      = ret_code    " Anzahl ausgewählte Dateien, -1 bei Fehler
                                                  user_action             = lv_action ).


    IF lv_action = cl_gui_frontend_services=>action_ok.
* Browserfenster erzeugen
      DATA(o_html) = NEW cl_gui_html_viewer( parent = cl_gui_container=>default_screen ).

* PDF im ABAP-Fenster anzeigen
      o_html->show_url( url      = it_sel_filetab[ 1 ]-filename
                        in_place = abap_true ).

* leere SAP-Toolbar ausblenden
      cl_abap_list_layout=>suppress_toolbar( ).

* cl_gui_container=>default_screen erzwingen
      WRITE: / space.
    ENDIF.

  CATCH cx_root INTO DATA(e_txt).
    WRITE: / e_txt->get_text( ).
ENDTRY.

[ABAP] OpenSQL: Vergleich von SELECT-Abfragen über RANGES, FOR ALL ENTRIES, JOINS

Allgemein

In den folgenden Beispielen werden drei der gängigen Datenbankzugriffe über ein SELECT nach Laufzeit sowie Vor- und Nachteilen verglichen.

Variante 1 (RANGE)

* Laufzeit: 0,086142s

* Vorteile:
*   - Aufteilen und Manipulieren von verknüpften DB-Abfragen
*   - Abfrage in einem Block -> gut für kleine Abfragen mit wenigen RANGE-Einträgen
*   - Verwendung z.B. bei Nutzung von SELECT-OPTIONS
* Nachteile:
*   - Laufzeitverhalten bei großen Abfragen
*   - keine Abhängigkeiten von zwei oder mehr Feldern in einem RANGE abbildbar (Verknüpfung in der WHERE-Clause erfolgt nur einzeln über AND/OR)
*   - RANGES werden beim SELECT in ein Statement mit vielen ORs umgewandelt
*     -> abhängig vom DB-System kommt es früher oder später zu DUMPS, wenn der RANGE zu viele Einträge beinhaltet (Speichergröße der RANGE-Table > 64kB)
DATA: lv_maktx TYPE maktx VALUE '<empty>'.

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

* SELECT 1: Materialnummern
SELECT m~matnr, @lv_maktx AS maktx
  INTO TABLE @DATA(it_mara)
  FROM mara AS m
  UP TO 1000 ROWS.

DATA: rg_matnr TYPE RANGE OF matnr.

* MATNR in RANGE kopieren, darauf achten, dass die Suchfelder UNIQUE sind
rg_matnr = VALUE #( FOR <m> IN it_mara
                    (
                      sign   = 'I'
                      option = 'EQ'
                      low    = <m>-matnr
                      high   = ''
                    ) ).

* SELECT 2: Kurztexte
SELECT t~matnr, t~maktx
  INTO TABLE @DATA(it_makt)
  FROM makt AS t
  WHERE t~matnr IN @rg_matnr
    AND t~spras = @sy-langu.

* Zuweisung MATNR, MAKTX
LOOP AT it_mara ASSIGNING FIELD-SYMBOL(<t>).
  IF line_exists( it_makt[ matnr = <t>-matnr ] ).
    <t>-maktx = it_makt[ matnr = <t>-matnr ]-maktx.
  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'.

cl_demo_output=>display( it_mara  ).

Variante 2 (FOR ALL ENTRIES)

* Laufzeit: 0,073252s

* Vorteile:
*   - Aufteilen und Manipulieren von verknüpften DB-Abfragen
*   - mehrere FOR ALL ENTRIES können pro Statement verwendet werden
*   - Verwendung z.B. bei Verarbeitung von vielen Datensätzen
* Nachteile:
*   - Laufzeitverhalten bei großen Abfragen
*   - wenn die FOR ALL ENTRIES Liste leer ist, wir die WHERE-Clause ignoriert, was zu unerwünschten Nebeneffekten führen kann
*   - FOR ALL ENTRIES werden beim SELECT in viele einzelne Statements umgewandelt
*   - man sollte darauf achten, dass die Einträge in der FOR ALL ENTRIES-Tabelle nur einmal auftreten -> Performance
*   - Speicherverbrauch durch die vielen Abfragen
* Anmerkungen:
*   - doppelte Einträge in der FOR ALL ENTRIES Tabelle werden entfernt (SELECT DISTINCT)
*   - wichtige Parameter für die Performance von FOR ALL ENTRIES sind:
*     rsdb/max_blocking_factor
*     rsdb/min_blocking_factor
*     rsdb/max_in_blocking_factor
*     rsdb/min_in_blocking_factor
*     rsdb/prefer_in_itab_opt
*     rsdb/prefer_fix_blocking
DATA: lv_maktx TYPE maktx VALUE '<empty>'.

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

* SELECT 1: Materialnummern
* darauf achten, dass die Einträge in der FOR ALL ENTRIES Tabelle UNIQUE sind
SELECT m~matnr, @lv_maktx AS maktx
  INTO TABLE @DATA(it_mara)
  FROM mara AS m
  UP TO 1000 ROWS.

* Prüfung auf IS INITIAL ist wichtig, da sonst die WHERE-Clause im SELECT ignoriert würde
IF NOT it_mara IS INITIAL.

* SELECT 2: Kurztexte
  SELECT t~matnr, t~maktx
    INTO TABLE @DATA(it_makt)
    FROM makt AS t
    FOR ALL ENTRIES IN @it_mara
    WHERE t~matnr = @it_mara-matnr
      AND t~spras = @sy-langu.

* Zuweisung MATNR, MAKTX
  LOOP AT it_mara ASSIGNING FIELD-SYMBOL(<m>).
    IF line_exists( it_makt[ matnr = <m>-matnr ] ).
      <m>-maktx = it_makt[ matnr = <m>-matnr ]-maktx.
    ENDIF.
  ENDLOOP.
ENDIF.

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

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

cl_demo_output=>display( it_mara  ).

Variante 3 (JOIN)

* Laufzeit: 0,012196s

* Vorteile:
*   - wesentlich schneller als RANGE und FOR ALL ENTRIES
*   - eine komplexe DB-Anfrage (generisch)
*   - Verwendung bei Verarbeitung von vielen Datensätzen verteilt über viele Tabellen
* Nachteile:
*   - komplexe Statements
*   - schlecht zu Debuggen
DATA(o_timer) = cl_abap_runtime=>create_hr_timer( ).
DATA(usec_start) = o_timer->get_runtime( ).

* SELECT: Materialnummern, Kurztexte
SELECT m~matnr, t~maktx
  INTO TABLE @DATA(it_mara)
  FROM mara AS m
  RIGHT OUTER JOIN makt AS t ON ( m~matnr = t~matnr )
  UP TO 1000 ROWS
  WHERE t~spras = @sy-langu.

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

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

cl_demo_output=>display( it_mara  ).

Links

[SAP] Archiv / Barcodes

Transaktionen

OANR (Nummernkreispflege: ARCHIVELNK)
OAM1 (ArchiveLink: Monitoring)
OABO (Anzeige offener Barcodes)
OAQI (SAP ArchiveLink: Queues anlegen)
OAC0 (CMS Customizing Content Repositories)

  • Zeile markieren
  • Button “Detail”

OAC2 (SAP ArchiveLink Dokumentarten global)

  • Dokumentart (AR_OBJECT)
  • Langbezeichung (OBJECTTEXT)
  • Dokumenttyp (DOC_TYPE)

OAC3 (SAP ArchiveLink Verknüpfungen)

  • Objekttyp (SAP_OBJECT)
  • Dokumentart (AR_OBJECT)
  • Contend Repository ID (ARCHIV_ID)
  • Verknüpfung (CONNECTION, TOA0x)

OAC5 (SAP ArchiveLink Barcodeerfassung)

QAER (Anzeige Archivobjekte)
OAAD (ArchiveLink Administration Dokumente)

SBDS1 (Anzeige offener Barcodes)
SBDS2 (Offene interne Barcodes)
SBDS3 (Offene externe Barcodes)
SBDS7 (Abgleich offener Barcodes)

Tabellen

CREP (KPRO CMS: Content-Repositories)
CREPDESCR (KPRO CMS: Beschreibungen der Content-Repositories)
CREP_HTTP (KPRO CMS: Content-Repositories (HTTP))
CREP_R3DB (KPRO CMS: Content-Repositories (R3DB))
SDOKSTCA (SDOK: Speicherkategorien physischer Informationsobjekte)
TOAOM (SAP ArchiveLink: Metatabelle für Verknüpfungen)
TOADV (SAP ArchiveLink: Globale Dokumentarten SAP ArchiveLink)
TOASP (SAP ArchiveLink language tab for archivobjects)
TOACM (Barcode-Erfassung von eingehenden Dokumenten)
TOABA (Barcodetypen-Tabelle SAP ArchiveLink)
TOASB (Sprachtabelle für TOABA)

Links