From 8bc216380d4f632b3e9b356f0e9da02432675465 Mon Sep 17 00:00:00 2001 From: danrega <16720986+danrega@users.noreply.github.com> Date: Tue, 2 Jan 2024 16:44:13 +0100 Subject: [PATCH] Update --- 06_Dynamic_Programming.md | 182 +++++++++++++++++++++++++++++++++++--- 1 file changed, 172 insertions(+), 10 deletions(-) diff --git a/06_Dynamic_Programming.md b/06_Dynamic_Programming.md index b48d0f8..b780620 100644 --- a/06_Dynamic_Programming.md +++ b/06_Dynamic_Programming.md @@ -153,18 +153,18 @@ ASSIGN num TO FIELD-SYMBOL(). TYPES c_len_3 TYPE c LENGTH 3. DATA(chars) = 'abcdefg'. -FIELD-SYMBOLS TYPE c_len_3. +FIELD-SYMBOLS TYPE c_len_3. "Implicit casting -ASSIGN chars TO CASTING. +ASSIGN chars TO CASTING. "abc FIELD-SYMBOLS TYPE data. "Explicit casting -ASSIGN chars TO CASTING TYPE c_len_3. +ASSIGN chars TO CASTING TYPE c_len_3. "abc DATA chars_l4 TYPE c LENGTH 4. -ASSIGN chars TO CASTING LIKE chars_l4. +ASSIGN chars TO CASTING LIKE chars_l4. "abcd ``` > **💡 Note**
@@ -210,7 +210,8 @@ LOOP AT itab ASSIGNING . ... ENDLOOP. -"Inline declaration of a field symbol. It receives a suitable +"Inline declaration of a field symbol. The field symbol is implcitly typed +"with the generic type data. "type automatically. LOOP AT itab ASSIGNING FIELD-SYMBOL(). -carrid = ... @@ -686,7 +687,7 @@ ASSIGN ('DOBJ') TO FIELD-SYMBOL(). "The statements set the sy-subrc value. No exception occurs in "case of an unsuccessful assignment. -ASSIGN ('DOESNOTEXIST') TO . +ASSIGN ('DOES_NOT_EXIST') TO . IF sy-subrc <> 0. ... ENDIF. @@ -893,8 +894,8 @@ DATA(gen_comp) = CONV string( -('COL2') ). "has a generic type. The components of the structure are accessed dynamically in "a DO loop. The sy-index value is interpreted as the position of the component "in the structure. Plus, using RTTI - as also shown further down - the component -"name is retrieved. Component names and the values are added to a string. As a -"prerequisite, all component values can be converted to type string. +"names are retrieved. Component names and the values are added to a string. As a +"prerequisite, all component values must be convertible to type string. DATA struc2string TYPE string. FIELD-SYMBOLS TYPE data. ASSIGN st TO . @@ -998,7 +999,7 @@ ENDIF. "------- Table expressions ------ "Similar to READ TABLE statements, you can specify table lines with 3 alternatives: "index read, read using free key, table key -"Also there, dynamic specification are possible regarding the key specifications. +"Also there, dynamic specifications are possible regarding the key specifications. "Reading based on index with dynamic key specifications "Specifying the secondary table index of a sorted secondary key @@ -1137,7 +1138,7 @@ SELECT * INTO TABLE @fli_tab. "Excursion: Compatible target data objects -"In the examples above, the data object/type was created statically. +"In the examples above, the data object/type is created statically. "Creating an anonymous data object with a CREATE DATA statement "and specifiying the type dynamically. @@ -1177,6 +1178,19 @@ SELECT * WHERE (where_clause) INTO TABLE NEW @DATA(tab_dyn_where). +"Dynamic ORDER BY clause +SELECT * + FROM zdemo_abap_fli + ORDER BY (`FLDATE`) + INTO TABLE NEW @DATA(tab_dyn_order). + +"SELECT statement with miscellaneous dynamic specifications +SELECT (`CARRID, CONNID, FLDATE`) + FROM (`ZDEMO_ABAP_FLI`) + WHERE (`CARRID <> ``AA```) + ORDER BY (`FLDATE`) + INTO TABLE NEW @DATA(tab_dyn_misc). + "Further dynamic specifications in other ABAP SQL statements "Creating a structure to be inserted into the database table SELECT SINGLE * @@ -1197,6 +1211,154 @@ DELETE FROM (table) WHERE (`CARRID = 'YZ'`).

⬆️ back to top

+**Excursion**: To take up the use case mentioned in the introduction about retrieving the content of a database table, storing it in an internal table, and +displaying it when the database table name is specified dynamically at +runtime, see the following code snippet. Note the comments. + + +```abap +CLASS zcl_example_class DEFINITION + PUBLIC + FINAL + CREATE PUBLIC . + + PUBLIC SECTION. + INTERFACES if_oo_adt_classrun. + PROTECTED SECTION. + PRIVATE SECTION. +ENDCLASS. +CLASS zcl_example_class IMPLEMENTATION. + METHOD if_oo_adt_classrun~main. + "The example retrieves the content of a database table, storing it in an + "internal table, and displaying it when the database table name is + "specified dynamically at runtime. + "Certainly, there are quite some ways to achieve it, and that work out + "of the box. For example, in ABAP for Cloud Development, you can implement + "the classrun if_oo_adt_classrun and output content using the out->write(...) + "method. You can also inherit from cl_demo_classrun in your class. In + "classic ABAP, you can, for example and additionally, use cl_demo_output or + "ALV. + "Notes: + "- The following example is just ABAP code tinkering with dynamic programming + " aspects. Note the disclaimer in the README of the cheat sheet repository. + " It is an example that sets its focus on a dynamic SELECT statement and + " processing internal tablecontent by dynamically accessing structure + " components. + "- The ways mentioned above are way more powerful (e.g. in most cases also + " nested and deep data objects can be displayed for demo purposes). + "- For simplicity, column contents are converted to string here if necessary, + " i.e. all column contents must be convertible to string. + "- For display purposes, the snippet uses the classrun methods to display + " results sequentially - instead of displaying the internal table + " content retrieved by the SELECT statement directly. + "- The example uses database tables from the cheat sheet repository. To fill + " them, you can use the method call zcl_demo_abap_aux=>fill_dbtabs( ).. + zcl_demo_abap_aux=>fill_dbtabs( ). + + "Data objects and types relevant for the example (length and offset for + "content display) + DATA str TYPE string. + TYPES: BEGIN OF comp_struc, + name TYPE string, + len TYPE i, + off TYPE i, + END OF comp_struc. + DATA it_comps TYPE TABLE OF comp_struc WITH EMPTY KEY. + + "Database table of type string containing names of database tables; + "table is looped over to output content of all database tables + DATA(dbtabs) = VALUE string_table( ( `ZDEMO_ABAP_CARR` ) + ( `ZDEMO_ABAP_FLI` ) + ( `ZDEMO_ABAP_FLSCH` ) ). + + LOOP AT dbtabs INTO DATA(dbtab). + "Retrieving database content of a dynamically specified database table + TRY. + SELECT * + FROM (dbtab) + INTO TABLE NEW @DATA(itab) + UP TO 5 ROWS. + CATCH cx_sy_dynamic_osql_semantics INTO DATA(sql_error). + CLEAR itab->*. + out->write( |Table { dbtab } does not exist.| ). + ENDTRY. + + IF sql_error IS INITIAL. + "Getting table component names using RTTI methods + TRY. + DATA(type_descr_obj_tab) = CAST cl_abap_tabledescr( + cl_abap_typedescr=>describe_by_data( itab->* ) ). + DATA(tab_comps) = CAST cl_abap_structdescr( + type_descr_obj_tab->get_table_line_type( ) )->get_components( ). + LOOP AT tab_comps ASSIGNING FIELD-SYMBOL(). + APPEND VALUE #( name = -name len = strlen( -name ) ) TO it_comps. + ENDLOOP. + CATCH cx_sy_move_cast_error INTO DATA(error). + ENDTRY. + + IF error IS INITIAL. + out->write( |\n| ). + out->write( |Retrieved content of database table { dbtab }:| ). + "Implementation for properly aligning the content + "The example is implemented to check the length of the column names as well as the + "length of the values in the columns. It determines the length of the longest string + "in each column. Depending on the length values, either the length of the column name + "or the length of the longest string in a column is stored in an internal table that + "contains information for calculating the offset. + LOOP AT tab_comps ASSIGNING FIELD-SYMBOL(). + ASSIGN it_comps[ name = -name ] TO FIELD-SYMBOL(). + DATA(max_content) = REDUCE i( INIT len = -len + FOR IN itab->* + NEXT len = COND #( WHEN strlen( CONV string( -(-name) ) ) > len + THEN strlen( CONV string( -(-name) ) ) + ELSE len ) ). + "Extend the length value to leave some more space + IF max_content > -len. + -len = max_content + 3. + ELSE. + -len += 3. + ENDIF. + ENDLOOP. + "Calculating offset values + DATA max_str_len TYPE i. + LOOP AT it_comps ASSIGNING FIELD-SYMBOL(). + DATA(tabix) = sy-tabix. + READ TABLE it_comps INDEX tabix - 1 ASSIGNING FIELD-SYMBOL(). + -off = COND #( WHEN tabix = 1 THEN 0 ELSE -len + -off ). + max_str_len += -len. + ENDLOOP. + "Providing enough space so that table row content can be inserted based on + "the offset specification + SHIFT str BY max_str_len PLACES RIGHT. + "Adding the column names first + LOOP AT it_comps ASSIGNING FIELD-SYMBOL(
). + str = insert( val = str sub =
-name off =
-off ). + ENDLOOP. + out->write( str ). + "Processing all lines in the internal table containing the retrieved table rows + LOOP AT itab->* ASSIGNING FIELD-SYMBOL(). + CLEAR str. + SHIFT str BY max_str_len PLACES RIGHT. + DO. + TRY. + str = insert( val = str sub = -(sy-index) off = it_comps[ sy-index ]-off ). + CATCH cx_sy_assign_illegal_component cx_sy_range_out_of_bounds cx_sy_itab_line_not_found. + EXIT. + ENDTRY. + ENDDO. + out->write( str ). + ENDLOOP. + ENDIF. + out->write( |\n| ). + CLEAR: str, it_comps. + ENDIF. + ENDLOOP. + ENDMETHOD. +ENDCLASS. +``` + +

⬆️ back to top

+ ### Dynamic Invoke The following code snippet shows dynamically specifying [procedure](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenprocedure_glosry.htm "Glossary Entry") calls.