ajanzen.com Umgang mit zur Laufzeit erstellen Selektions-, Sortier- und IF-Bedingungen ajanzen.com 1 Einleitung In dem vorliegenden Dokument möchte ich auf die Möglichkeiten des Erstellens dynamischer Selektions-, Sortier- und IF-Bedingungen eingehen. Das Beispielcoding aus Kapitel 3 liefert keine Datenausgabe. Die Wirkung der einzelnen Anweisungen kann im Debugger gut nachverfolgt werden. Das komplette Beispielcoding ist in Kapitel 3 enthalten. Nähere Informationen zum Ablauf können Kapitel 2 entnommen werden. 1 ajanzen.com 2 Informationen zur Programmlogik Zu Beginn des Beispielprogrammes werden Informationen aus Tabelle SPFLI ermittelt. Die WHERE-Bedingung des Tabellenzugriffes wird in Form einer Variable vom Typ String mitgegeben. Dabei wird gezeigt, wie Literale und Variablen in den Suchstring eingebunden werden. Außerdem ist dem Coding auch das Vorgehen der dynamischen Angabe von Tabellennamen für einen Datenbankzugriff zu entnehmen. Nach dem SELECT wird auf den Einsatz einer dynamischen WHERE-Bedingung in der LOOP-Anweisung eingegangen. Aus Gründen der Einfachheit kommt hier die WHERE-Bedingung des Datenbankzugriffes zum Einsatz. Das nächste Beispiel befasst sich mit dem dynamischen Erstellen einer Sortieranweisung. Die einzelnen Sortierkriterien werden in Form einer Tabelle vom Typ ABAP_SORTORDER_TAB mitgegeben. Häufig wird in Zusammenhang mit dynamischen IF-Anweisungen nach folgender Syntax gesucht: IF (BEDINGUNG). Soweit mir bekannt ist, funktioniert dieses Vorgehen leider nicht. Die entsprechende Fragestellung kann jedoch recht einfach durch den Einsatz von Ranges gelöst werden. In dem Beispielcoding werden zwei Möglichkeiten der Range-Verwendung aufgezeigt. Die einfache Möglichkeit setzt auf eine Range-Struktur für ein CHAR-Datenelement. Da in der IF-Bedingung keine Prüfung auf Datentypkompatibilität stattfindet, können über diese Range-Struktur auch Prüfungen auf Dezimalzahlen erfolgen. Bei der etwas komplexeren Möglichkeit wird das Range-Objekt unter Verwendung des zu vergleichenden Feldes zur Laufzeit erstellt. Das Vorgehen kann eingesetzt werden, wenn die einfache Möglichkeit nicht ausreicht. 2 3 Coding *--------------------------------------------------------------------* * Das vorliegende Programm dient der Demonstration dynamisch * zusammengestellter Bedingungen für SELECT-, LOOP-, SORT- und IF* Anweisungen * * Date: 11.04.2015 *--------------------------------------------------------------------* * Änderungen *--------------------------------------------------------------------* REPORT zaj_gen_sort_when_check. DATA: gt_sflight TYPE flighttab. DATA: gs_sflight TYPE sflight. DATA: gv_where TYPE string. DATA: gv_table TYPE string. DATA: gv_carrid_dl TYPE s_carr_id. DATA: gt_sort_table TYPE abap_sortorder_tab. DATA: gs_sort_struct TYPE abap_sortorder. DATA: gr_err_dyn_sql TYPE REF TO cx_sy_dynamic_osql_semantics. DATA: gr_err_dyn_loop TYPE REF TO cx_sy_itab_dyn_loop. DATA: gt_err_ill_comp TYPE REF TO cx_sy_dyn_table_ill_comp_val. DATA: gv_err_msg TYPE string. DATA: gt_char_range TYPE STANDARD TABLE OF etrange. DATA: gs_char_range TYPE etrange. DATA: gt_comp TYPE cl_abap_structdescr=>component_table. DATA: gs_comp TYPE cl_abap_structdescr=>component. DATA: gr_struct_dscr TYPE REF TO cl_abap_structdescr. DATA: gr_table_dscr TYPE REF TO cl_abap_tabledescr. DATA: gr_err_table TYPE REF TO cx_sy_table_creation. DATA: gr_err_struct TYPE REF TO cx_sy_struct_creation. DATA: gr_range_tab TYPE REF TO data. FIELD-SYMBOLS: <gt_range_tab> TYPE ANY TABLE. FIELD-SYMBOLS: <gs_range_str> TYPE any. FIELD-SYMBOLS: <gv_value> TYPE any. START-OF-SELECTION. *************************************************************************** **** * Datenselektion *************************************************************************** **** * Selektionsbedingung zusammenstellen ... dabei können sowohl Variablen als auch * Literale eingebunden werden MOVE 'DL' TO gv_carrid_dl. MOVE 'CARRID EQ `AA` OR CARRID EQ `AZ` OR CARRID EQ gv_carrid_dl' TO gv_where. TRY . * Datenselektion mit fest vorgegebenen Tabelle SELECT * FROM sflight INTO CORRESPONDING FIELDS OF TABLE gt_sflight WHERE (gv_where). IF sy-subrc NE 0. * In diesem Fall wird eine leere Tabelle angezeigt ENDIF. * Datenselektion mit einer zur Laufzeit erstellten Tabelle MOVE 'SFLIGHT' TO gv_table. SELECT * FROM (gv_table) INTO CORRESPONDING FIELDS OF TABLE gt_sflight WHERE (gv_where). IF sy-subrc NE 0. * In diesem Fall wird eine leere Tabelle angezeigt ENDIF. CATCH cx_sy_dynamic_osql_semantics INTO gr_err_dyn_sql. * Um einen Kurzdump zu vermeiden, fangen wir die Ausnahme ab gv_err_msg = gr_err_dyn_sql->get_text( ). MESSAGE gv_err_msg TYPE 'S' DISPLAY LIKE 'E'. RETURN. ENDTRY. *************************************************************************** **** * LOOP über Tabellenfelder *************************************************************************** **** TRY . * Die Vorgehensweise ist wie beim SELECT LOOP AT gt_sflight INTO gs_sflight WHERE (gv_where). ENDLOOP. CATCH cx_sy_itab_dyn_loop INTO gr_err_dyn_loop. * Um einen Kurzdump zu vermeiden, fangen wir die Ausnahme ab gv_err_msg = gr_err_dyn_loop->get_text( ). MESSAGE gv_err_msg TYPE 'S' DISPLAY LIKE 'E'. RETURN. ENDTRY. *************************************************************************** **** * Sortieren von Daten *************************************************************************** **** * Sortierbedingung zusammenstellen MOVE abap_true TO gs_sort_struct-descending. MOVE 'CONNID' TO gs_sort_struct-name. APPEND gs_sort_struct TO gt_sort_table. MOVE abap_false TO gs_sort_struct-descending. MOVE 'FLDATE' TO gs_sort_struct-name. APPEND gs_sort_struct TO gt_sort_table. TRY . * und das eigentliche Sortieren SORT gt_sflight BY (gt_sort_table). CATCH cx_sy_dyn_table_ill_comp_val INTO gt_err_ill_comp. * Um einen Kurzdump zu vermeiden, fangen wir die Ausnahme ab gv_err_msg = gt_err_ill_comp->get_text( ). MESSAGE gv_err_msg TYPE 'S' DISPLAY LIKE 'E'. RETURN. ENDTRY. *************************************************************************** **** * Erstellen einer dynamischen IF-Bedingung ... der einfache Weg *************************************************************************** **** * ... der relativ einfache Weg über eine CHAR-Range-Struktur READ TABLE gt_sflight INTO gs_sflight INDEX 1. * ... Range vorbereiten MOVE 'I' TO gs_char_range-sign. MOVE 'EQ' TO gs_char_range-option. MOVE gs_sflight-paymentsum TO gs_char_range-low. APPEND gs_char_range TO gt_char_range. IF gs_sflight-paymentsum IN gt_char_range. WRITE: 'CHAR-Range funktionert'. ENDIF. *************************************************************************** **** * Erstellen einer dynamischen IF-Bedingung ... der komplexere aber * dynamischere Weg *************************************************************************** **** * Range-Struktur erstellen gs_comp-name = 'SIGN'. * Der Typ ist hier eine Instanz der Klasse CL_ABAP_ELEMDESCR gs_comp-type ?= cl_abap_datadescr=>describe_by_name( 'DDSIGN' ). APPEND gs_comp TO gt_comp. gs_comp-name = 'OPTION'. * Der Typ ist hier eine Instanz der Klasse CL_ABAP_ELEMDESCR gs_comp-type ?= cl_abap_datadescr=>describe_by_name( 'DDOPTION' ). APPEND gs_comp TO gt_comp. gs_comp-name = 'LOW'. * Der Typ ist hier eine Instanz der Klasse CL_ABAP_ELEMDESCR gs_comp-type ?= cl_abap_datadescr=>describe_by_data( gs_sflightpaymentsum ). APPEND gs_comp TO gt_comp. gs_comp-name = 'HIGH'. * Der Typ ist hier eine Instanz der Klasse CL_ABAP_ELEMDESCR gs_comp-type ?= cl_abap_datadescr=>describe_by_data( gs_sflightpaymentsum ). APPEND gs_comp TO gt_comp. TRY. * Strukturobjekt unter Verwendung der Komponententabelle erstellen gr_struct_dscr = cl_abap_structdescr=>create( gt_comp ). * Über das Strukturobjekt ein Tabellenobjekt erstellen gr_table_dscr = cl_abap_tabledescr=>create( gr_struct_dscr ). CATCH cx_sy_struct_creation INTO gr_err_struct. gv_err_msg = gr_err_struct->get_text( ). MESSAGE gv_err_msg TYPE 'S' DISPLAY LIKE 'E'. RETURN. CATCH cx_sy_table_creation INTO gr_err_table. gv_err_msg = gr_err_table->get_text( ). MESSAGE gv_err_msg TYPE 'S' DISPLAY LIKE 'E'. RETURN. ENDTRY. * Range-Objekt unter Verwendung der Klasse erstellen CREATE DATA gr_range_tab TYPE HANDLE gr_table_dscr. * Range mit Werten füllen ASSIGN gr_range_tab->* TO <gt_range_tab>. INSERT INITIAL LINE INTO TABLE <gt_range_tab> ASSIGNING <gs_range_str>. ASSIGN COMPONENT 'SIGN' OF STRUCTURE MOVE 'I' <gs_range_str> TO <gv_value>. TO <gv_value>. ASSIGN COMPONENT 'OPTION' OF STRUCTURE <gs_range_str> TO <gv_value>. MOVE 'EQ' TO <gv_value>. ASSIGN COMPONENT 'LOW' OF STRUCTURE MOVE gs_sflight-paymentsum <gs_range_str> TO <gv_value>. TO <gv_value>. IF gs_sflight-paymentsum IN <gt_range_tab>. WRITE: /, 'DATA-Range funktioniert'. ENDIF.