diff --git a/01_Internal_Tables.md b/01_Internal_Tables.md index 2c30dc5..080f31f 100644 --- a/01_Internal_Tables.md +++ b/01_Internal_Tables.md @@ -4,8 +4,8 @@ - [Internal Tables](#internal-tables) - [Introduction](#introduction) - - [Basic Properties of Internal Tables](#basic-properties-of-internal-tables) - - [Table Keys (Primary, Secondary, Standard, Empty) and Table Indexes](#table-keys-primary-secondary-standard-empty-and-table-indexes) + - [Basic Properties of Internal Tables](#basic-properties-of-internal-tables) + - [Table Keys (Primary, Secondary, Standard, Empty) and Table Indexes](#table-keys-primary-secondary-standard-empty-and-table-indexes) - [Creating Internal Tables and Types](#creating-internal-tables-and-types) - [Specifying Keys in Internal Table Declarations](#specifying-keys-in-internal-table-declarations) - [Internal Tables Based on Locally Created Line/Table Types](#internal-tables-based-on-locally-created-linetable-types) @@ -34,31 +34,31 @@ - [BINARY SEARCH Addition: Optimized Read Access When Specifying Free Keys](#binary-search-addition-optimized-read-access-when-specifying-free-keys) - [Example: Exploring READ TABLE Statements and Table Expressions](#example-exploring-read-table-statements-and-table-expressions) - [Table Expressions](#table-expressions) - - [Getting Information about Internal Tables, Table Lines, Table Types](#getting-information-about-internal-tables-table-lines-table-types) - - [Checking the Existence of a Line in an Internal Table](#checking-the-existence-of-a-line-in-an-internal-table) - - [Checking the Index of a Line in an Internal Table](#checking-the-index-of-a-line-in-an-internal-table) - - [Checking How Many Lines Exist in an Internal Table](#checking-how-many-lines-exist-in-an-internal-table) - - [Getting Table (Type) Information at Runtime](#getting-table-type-information-at-runtime) - [Processing Multiple Internal Table Lines Sequentially](#processing-multiple-internal-table-lines-sequentially) - [Restricting the Area of a Table to Be Looped Over](#restricting-the-area-of-a-table-to-be-looped-over) - [Defining the Step Size and the Direction of Loop Passes](#defining-the-step-size-and-the-direction-of-loop-passes) - [Iteration Expressions](#iteration-expressions) - [Interrupting and Exiting Loops](#interrupting-and-exiting-loops) - [Inserting and Deleting Lines in Internal Tables in Loops](#inserting-and-deleting-lines-in-internal-tables-in-loops) - - [Operations with Internal Tables Using ABAP SQL SELECT Statements](#operations-with-internal-tables-using-abap-sql-select-statements) - - [Internal Tables as Target Data Objects in SELECT Queries](#internal-tables-as-target-data-objects-in-select-queries) - - [SELECT Queries with Internal Tables as Data Sources](#select-queries-with-internal-tables-as-data-sources) - - [Restrictions Regarding Selecting from Internal Tables](#restrictions-regarding-selecting-from-internal-tables) - - [Excursion: Joining/Merging Internal Tables into Internal Tables](#excursion-joiningmerging-internal-tables-into-internal-tables) - - [Sorting Internal Tables](#sorting-internal-tables) - [Modifying Internal Table Content](#modifying-internal-table-content) - [Modifying Read Table Lines](#modifying-read-table-lines) - [Modifying Table Lines Using ABAP MODIFY Statements](#modifying-table-lines-using-abap-modify-statements) - [Deleting Internal Table Content](#deleting-internal-table-content) - [Deleting Adjacent Duplicate Lines](#deleting-adjacent-duplicate-lines) - [Deleting the Entire Internal Table Content](#deleting-the-entire-internal-table-content) + - [Sorting Internal Tables](#sorting-internal-tables) - [Grouping Internal Tables](#grouping-internal-tables) - [Collecting Values](#collecting-values) + - [Getting Information about Internal Tables, Table Lines, Table Types](#getting-information-about-internal-tables-table-lines-table-types) + - [Checking the Existence of a Line in an Internal Table](#checking-the-existence-of-a-line-in-an-internal-table) + - [Checking the Index of a Line in an Internal Table](#checking-the-index-of-a-line-in-an-internal-table) + - [Checking How Many Lines Exist in an Internal Table](#checking-how-many-lines-exist-in-an-internal-table) + - [Getting Table (Type) Information at Runtime](#getting-table-type-information-at-runtime) + - [Operations with Internal Tables Using ABAP SQL SELECT Statements](#operations-with-internal-tables-using-abap-sql-select-statements) + - [Internal Tables as Target Data Objects in SELECT Queries](#internal-tables-as-target-data-objects-in-select-queries) + - [SELECT Queries with Internal Tables as Data Sources](#select-queries-with-internal-tables-as-data-sources) + - [Restrictions Regarding Internal Tables as Data Sources in ABAP SQL SELECT Statements](#restrictions-regarding-internal-tables-as-data-sources-in-abap-sql-select-statements) + - [Excursion: Joining/Merging Internal Tables into Internal Tables](#excursion-joiningmerging-internal-tables-into-internal-tables) - [Excursions](#excursions) - [Improving Read Performance with Secondary Table Keys](#improving-read-performance-with-secondary-table-keys) - [Example: Exploring Read Access Performance with Internal Tables](#example-exploring-read-access-performance-with-internal-tables) @@ -88,7 +88,7 @@ Internal Tables ...

⬆️ back to top

-## Basic Properties of Internal Tables +### Basic Properties of Internal Tables
🟢 Click to expand for more details @@ -141,7 +141,7 @@ Internal Tables ...

⬆️ back to top

-## Table Keys (Primary, Secondary, Standard, Empty) and Table Indexes +### Table Keys (Primary, Secondary, Standard, Empty) and Table Indexes
🟢 Click to expand for more details @@ -481,7 +481,9 @@ This section explores various line and table type options when declaring interna ``` abap -"------ Internal tables declared using elementary line types ------ +*&---------------------------------------------------------------------* +*& Internal tables declared using elementary line types +*&---------------------------------------------------------------------* "Note: In this case, the whole table line is the standard table key. "Elementary built-in ABAP types @@ -529,7 +531,9 @@ DATA it_elem_11 TYPE TABLE OF zdemo_abap_carr_ve-url WITH EMPTY KEY. ``` abap -"------ Internal tables declared using structured types ------ +*&---------------------------------------------------------------------* +*& Internal tables declared using structured types +*&---------------------------------------------------------------------* "Locally declared structured type TYPES: BEGIN OF local_struct, @@ -581,7 +585,9 @@ DATA it_struc_7 TYPE TABLE OF loc_deep_struct WITH EMPTY KEY. ``` abap -"------ Internal tables declared using table types ------ +*&---------------------------------------------------------------------* +*& Internal tables declared using table types +*&---------------------------------------------------------------------* "Locally declared table type (based on a locally declared structured type) TYPES: BEGIN OF loc_struct, @@ -991,6 +997,25 @@ itab = VALUE #( ( comp1 = a comp2 = b ...)                 ... ). ``` + + + + + Iteration expressions with FOR expressions + + +Using the `VALUE` operator and iteration expressions with [`FOR`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenfor.htm), you can create content of an internal table by evaluating one or more source tables. The expressions are covered in the [Constructor Expressions](05_Constructor_Expressions.md) cheat sheet. +
+ +```abap +TYPES ty_int_tab TYPE TABLE OF i WITH EMPTY KEY. +DATA(int_table_a) = VALUE ty_int_tab( ( 1 ) ( 2 ) ( 3 ) ( 4 ) ( 5 ) ). +DATA int_table_b TYPE ty_int_tab. +int_table_b = VALUE #( FOR wa_b IN int_table_a ( wa_b * 2 ) ). +"Table Content: 2 / 4 / 6 / 8 / 10 +``` + + @@ -1006,13 +1031,14 @@ itab = VALUE #( ( comp1 = a comp2 = b ...) Subject Details/Code Snippet - Copying the content of another internal table + Copying the content of another (incompatible) internal table ... using the [`CORRESPONDING`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenconstructor_expr_corresponding.htm) operator. - Note that the existing content is deleted. - As an alternative to the `CORRESPONDING` operator, you can use [`MOVE-CORRESPONDING`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapmove-corresponding.htm) statements. +- The operator is particularly useful for incompatible source and target types. Value assignments are made based on identical components in the source and target. As shown further down, you can also specify mapping rules using the `MAPPING` addition. - The example assumes that the line types of the source and target table are not compatible. However, if the line types are compatible, the syntax will also work. - Several additions are possible. They can also be combined. Check the ABAP Keyword Documentation. @@ -1988,7 +2014,9 @@ DATA(itab) = VALUE t_type_so( ( comp1 = 1 comp2 = 'lorem' comp3 = 30 comp4 = 'ip DATA wa TYPE s_demo. -"--------- WHERE condition with comparison expressions --------- +*&---------------------------------------------------------------------* +*& WHERE condition with comparison expressions +*&---------------------------------------------------------------------* "Examples: =/EQ, <>/NE, >/GT, =,GE, <=/LE, " CO, CN, CA, NA, CS, NS, CP, NP, @@ -2010,7 +2038,9 @@ ASSERT sy-tabix = 2. READ TABLE itab INTO wa WHERE comp2 CS 'd'. ASSERT sy-tabix = 2. -"--------- WHERE condition with predicate expressions --------- +*&---------------------------------------------------------------------* +*& WHERE condition with predicate expressions +*&---------------------------------------------------------------------* "Examples: IS [NOT] INITIAL " IS [NOT] BOUND @@ -2019,7 +2049,9 @@ ASSERT sy-tabix = 2. READ TABLE itab INTO wa WHERE comp1 > 4 AND comp4 IS INITIAL. ASSERT sy-tabix = 5. -"--------- WITH KEY instead of WHERE condition --------- +*&---------------------------------------------------------------------* +*& WITH KEY instead of WHERE condition +*&---------------------------------------------------------------------* "Syntax warning in READ TABLE ... WHERE ... statements READ TABLE itab INTO wa WHERE comp4 IS INITIAL. @@ -2034,7 +2066,9 @@ ASSERT sy-tabix = 5. READ TABLE itab INTO wa WHERE comp4 IS INITIAL ##read_where_ok. ASSERT sy-tabix = 5. -"------------------- Further additions ------------------- +*&---------------------------------------------------------------------* +*& Further additions +*&---------------------------------------------------------------------* "TRANSPORTING NO FIELDS addition is possible READ TABLE itab TRANSPORTING NO FIELDS WHERE comp2 CS 'd'. @@ -2047,7 +2081,9 @@ ASSERT sy-tabix = 3. READ TABLE itab USING KEY sk INTO wa WHERE comp3 > 40. ASSERT sy-tabix = 5. -"------------------- Excursions ------------------- +*&---------------------------------------------------------------------* +*& Excursions +*&---------------------------------------------------------------------* "Note the comparison rules for character-like data types READ TABLE itab INTO wa WHERE comp2 = 'lorem' ##read_where_ok. @@ -2080,7 +2116,9 @@ LOOP AT itab INTO wa WHERE comp2 CS 'd'. EXIT. ENDLOOP. -"------------------- Dynamic WHERE condition ------------------- +*&---------------------------------------------------------------------* +*& Dynamic WHERE condition +*&---------------------------------------------------------------------* "Character-like data objects or standard tables with character-like line type "can be specified @@ -2921,7 +2959,7 @@ itab_so = itab. DATA line TYPE s_demo. -"------ Reading table line by index------ +"Reading table line by index "Just specifying the index number means referring to the primary table index. "In this case, the internal table must be an index table. @@ -2972,7 +3010,9 @@ DATA(line_hashed_tab3) = itab_hashed[ KEY sk INDEX 2 ].
``` abap -"------------------ TABLE KEY addition ------------------ +*&---------------------------------------------------------------------* +*& TABLE KEY addition +*&---------------------------------------------------------------------* "Explicitly specifying the primary table key line = itab[ TABLE KEY primary_key COMPONENTS comp1 = 1 ]. @@ -2995,7 +3035,9 @@ line = itab[ TABLE KEY sk comp2 = 20 comp3 = 21 ]. "line = itab[ TABLE KEY sk comp2 = 20 ]. -"------------------ KEY addition ------------------ +*&---------------------------------------------------------------------* +*& KEY addition +*&---------------------------------------------------------------------* "Using KEY and specifying all key components work like specifying TABLE KEY line = itab[ KEY primary_key COMPONENTS comp1 = 1 ]. @@ -3031,8 +3073,9 @@ line = itab[ comp2 = 10 ] ##primkey[sk]. "Specifying the key name line = itab[ KEY sk comp2 = 10 ]. - -"------------------ No TABLE KEY/KEY additions ------------------ +*&---------------------------------------------------------------------* +*& No TABLE KEY/KEY additions +*&---------------------------------------------------------------------* "Specifying a free key search, but including all components of the primary "table key @@ -3558,209 +3601,6 @@ ENDCLASS.

⬆️ back to top

- -## Getting Information about Internal Tables, Table Lines, Table Types - -### Checking the Existence of a Line in an Internal Table - -This is relevant if you are not interested in the content of a table -line, but only want to find out whether a line exists that matches to the -index or key specifications. To do this, use a [`READ TABLE`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapread_table.htm) -statement with the `TRANSPORTING NO FIELDS` addition. The -addition indicates that no actual content is to be read. If the search was -successful and an entry exists, the system field `sy-subrc` is -set to 0. - -A newer way to check the existence of a line is the [predicate -function](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenpredicate_function_glosry.htm "Glossary Entry") -[`line_exists( )`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenline_exists_function.htm). -This function expects a [table -expression](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abentable_expression_glosry.htm "Glossary Entry") as an argument. -See below for more on table expressions. Note that table expressions do not set system fields. -``` abap -"Read using a key -READ TABLE it WITH KEY b = 2 TRANSPORTING NO FIELDS. - -IF sy-subrc = 0. - ... -ENDIF. - -"Read using the index -READ TABLE it INDEX 1 TRANSPORTING NO FIELDS. - -IF sy-subrc = 0. - ... -ENDIF. - -"Read using the key -IF line_exists( it[ b = 2 ] ). - ... -ENDIF. - -"Read using the index -IF line_exists( it[ 1 ] ). - ... -ENDIF. -``` - -

⬆️ back to top

- -### Checking the Index of a Line in an Internal Table - -If you want to find out about the index of a line in an internal table, you can also make use of the `READ TABLE` statement above. If -the line is found, the system field `sy-tabix` is set to the number of the index. Otherwise, the built-in function -[`line_index( )`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenline_index_function.htm) can be used. It returns the index of the found line or 0 if the line does not exist. - -``` abap -DATA(itab) = VALUE string_table( ( `aaa` ) ( `bbb` ) ). -READ TABLE itab WITH KEY table_line = `bbb` TRANSPORTING NO FIELDS. -"2 -DATA(tabix) = sy-tabix. - -"1 -DATA(idx) = line_index( itab[ table_line = `aaa` ] ). - -"Note: No primary table index with hashed tables -DATA(hashed_tab) = VALUE string_hashed_table( ( `a` ) ( `b` ) ( `c` ) ). -"-1 -DATA(hashed_primary_idx) = line_index( hashed_tab[ table_line = `c` ] ). - -"Index access in hashed tables only using a secondary table index -TYPES: BEGIN OF s, - comp1 TYPE i, - comp2 TYPE i, - END OF s, - ttype TYPE HASHED TABLE OF s WITH UNIQUE KEY comp1 WITH NON-UNIQUE SORTED KEY sk COMPONENTS comp2. - -DATA(hashed_tab2) = VALUE ttype( ( comp1 = 1 comp2 = 10 ) - ( comp1 = 2 comp2 = 8 ) - ( comp1 = 3 comp2 = 9 ) ). - -"3 -DATA(hashed_secondary_idx) = line_index( hashed_tab2[ KEY sk comp2 = 10 ] ). -"1 -hashed_secondary_idx = line_index( hashed_tab2[ KEY sk comp2 = 8 ] ). -``` - -

⬆️ back to top

- -### Checking How Many Lines Exist in an Internal Table - -`lines( )` is another built-in function that you can use to check how many lines exist in an internal table. It returns an integer value. - -``` abap -DATA(itab) = VALUE string_table( ( `a` ) ( `b` ) ( `c` ) ( `d` ) ( `e` ) ). - -"5 -DATA(number_of_lines) = lines( itab ). - -"Excursion: Finding out the number of lines in a table by specifying concrete -"component values, e.g. you want to find out how many lines exist in the table -"that have the value 1 for comp2 -TYPES: BEGIN OF struct, - comp1 TYPE c LENGTH 3, - comp2 TYPE i, - END OF struct, - tab_type TYPE TABLE OF struct WITH EMPTY KEY. - -DATA(it) = VALUE tab_type( ( comp1 = 'a' comp2 = 1 ) - ( comp1 = 'b' comp2 = 1 ) - ( comp1 = 'c' comp2 = 1 ) - ( comp1 = 'd' comp2 = 2 ) - ( comp1 = 'e' comp2 = 3 ) - ( comp1 = 'f' comp2 = 4 ) - ( comp1 = 'g' comp2 = 5 ) ). - -"7 -DATA(line_num) = lines( it ). - -"Finding out the number of lines in a table by component value, e.g. -"using constructor expressions and specifying a WHERE clause. -"The example creates an new internal table inline using VALUE and a FOR loop, -"specified with a WHERE clause. The lines function is applied to the -"table created inline. -"3 -DATA(line_num_filtered1) = lines( VALUE tab_type( FOR wa IN it WHERE ( comp2 = 1 ) ( wa ) ) ). - -"Using the REDUCE operator -"The example adds 1 to the resulting integer if the comp2 value of the iterated line is greater than 1. -"The lines function is not relevant in the example. -"4 -DATA(line_num_filtered2) = REDUCE i( INIT var = 0 - FOR IN it - WHERE ( comp2 > 1 ) - NEXT var += 1 ). - -"Using the FILTER operator -"Note: The source table must have at least one sorted key or a hash key for accessing. -"If the table does not have such a primary table key, a secondary table key must be available. -TYPES: tab_type_sorted TYPE TABLE OF struct with NON-UNIQUE SORTED KEY sec_key COMPONENTS comp2. -DATA it_sorted type tab_type_sorted. -it_sorted = it. - -"The example creates an new internal table inline using FILTER, -"specified with a WHERE clause. The lines function is applied to the -"table created inline. -"3 -DATA(line_num_filtered3) = lines( FILTER #( it_sorted USING KEY sec_key WHERE comp2 = 1 ) ). -"4 -DATA(line_num_filtered4) = lines( FILTER #( it_sorted USING KEY sec_key WHERE comp2 > 1 ) ). - -"Using LOOP statements -CLEAR number_of_lines. -"No WHERE condition as all lines shall be processed -"7 -LOOP AT it REFERENCE INTO DATA(line). - number_of_lines += 1. -ENDLOOP. - -CLEAR number_of_lines. -"3 -LOOP AT it transporting no fields where comp2 = 1. - number_of_lines += 1. -ENDLOOP. -``` - -

⬆️ back to top

- -### Getting Table (Type) Information at Runtime - -Using [Runtime Type Identification (RTTI)](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenrun_time_type_identific_glosry.htm "Glossary Entry"), -you can get type information on internal tables and table types at runtime. - -For more information, see the [Dynamic Programming](06_Dynamic_Programming.md) ABAP cheat sheet. - -RTTI example: -```abap -TYPES tab_type TYPE SORTED TABLE OF zdemo_abap_flsch - WITH UNIQUE KEY carrid connid - WITH NON-UNIQUE SORTED KEY sec_key ALIAS sk COMPONENTS countryfr cityto. -DATA itab TYPE tab_type. - -DATA(tdo_d) = cl_abap_typedescr=>describe_by_data( itab ). -"DATA(tdo_d) = cl_abap_typedescr=>describe_by_name( 'TAB_TYPE' ). - -"Cast to get more specific information -DATA(tdo_itab) = CAST cl_abap_tabledescr( cl_abap_typedescr=>describe_by_data( itab ) ). -"DATA(tdo_itab) = CAST cl_abap_tabledescr( tdo_d ). - -DATA(type_category_itab) = tdo_itab->kind. -DATA(relative_name_itab) = tdo_itab->get_relative_name( ). -... "Explore more options by positioning the cursor behind -> and choosing CTRL + Space -DATA(table_kind_itab) = tdo_itab->table_kind. -DATA(table_keys_itab) = tdo_itab->key. -DATA(table_keys_more_details_itab) = tdo_itab->get_keys( ). -DATA(table_has_unique_key_itab) = tdo_itab->has_unique_key. -DATA(table_key_alias_itab) = tdo_itab->get_key_aliases( ). -DATA(line_type_itab) = tdo_itab->get_table_line_type( ). -DATA(table_component_info_itab) = CAST cl_abap_structdescr( tdo_itab->get_table_line_type( ) ). -DATA(table_components_itab) = CAST cl_abap_structdescr( tdo_itab->get_table_line_type( ) )->components. -DATA(table_comps_more_info_itab) = CAST cl_abap_structdescr( tdo_itab->get_table_line_type( ) )->get_components( ). -DATA(applies_to_data_itab) = tdo_itab->applies_to_data( VALUE tab_type( ) ). -``` - -

⬆️ back to top

- ## Processing Multiple Internal Table Lines Sequentially If you are interested not only in single table lines, but in the entire @@ -3981,7 +3821,9 @@ TYPES: BEGIN OF s_loop_mod, DATA(itab_original) = VALUE t_loop_mod( FOR x = 1 WHILE x <= 10 ( text = x ) ). DATA(itab) = itab_original. -"---------- Inserting a line after the current line ---------- +*&---------------------------------------------------------------------* +*& Inserting a line after the current line +*&---------------------------------------------------------------------* "The example inserts a line after the currently processed line "using an INSERT statement and specifying the index value @@ -4020,7 +3862,9 @@ ENDLOOP. *4 0 *... -"---------- Deleting a line after the current line ---------- +*&---------------------------------------------------------------------* +*& Deleting a line after the current line +*&---------------------------------------------------------------------* "The example deletes a line after the current line using a "DELETE statement and the INDEX addition. The index value @@ -4043,7 +3887,9 @@ ENDLOOP. *7 4 *9 5 -"---------- Inserting a line before the current line ---------- +*&---------------------------------------------------------------------* +*& Inserting a line before the current line +*&---------------------------------------------------------------------* "The example insert a line before the currently processed line using "an INSERT statement. The current sy-tabix value is used as INDEX value, @@ -4112,8 +3958,9 @@ ENDLOOP. *---- New line 10 ---- 19 *10 (existing line, index before insertion: 19) 20 - -"---------- Deleting a line before the current line ---------- +*&---------------------------------------------------------------------* +*& Deleting a line before the current line +*&---------------------------------------------------------------------* "The example explores the deletion of a line before the currently "processed line. The previous line in the table is deleted if @@ -4163,7 +4010,9 @@ ENDLOOP. *9 5 *10 6 -"---------- Deleting the currently processed table line ---------- +*&---------------------------------------------------------------------* +*& Deleting the currently processed table line +*&---------------------------------------------------------------------* "The example explores deleting the currently processed table line using "a string table. So, the DELETE statement specifies the current sy-tabix @@ -4191,7 +4040,9 @@ ENDLOOP. *i *j -"---------- Statements clearing the entire internal table are not allowed in loops ---------- +*&---------------------------------------------------------------------* +*& Statements clearing the entire internal table are not allowed in loops +*&---------------------------------------------------------------------* "The entire internal table cannot be deleted within loops. "The following statements commented out are not possible. @@ -4204,593 +4055,6 @@ ENDLOOP.

⬆️ back to top

-## Operations with Internal Tables Using ABAP SQL SELECT Statements - -### Internal Tables as Target Data Objects in SELECT Queries - -Adding multiple lines from a database table to an internal table using -[`SELECT`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapselect.htm), -for example, based on a condition. In the case below, the internal table -is created inline. -``` abap -SELECT FROM dbtab - FIELDS comp1, comp2 ... - WHERE ... - INTO TABLE @DATA(itab_sel). -``` - -Adding multiple lines from a database table using `SELECT`, for example, based on a condition when the database table has a line type that is incompatible with the internal table. The `*` character means that all fields are selected. The other examples define specific fields. -The `APPENDING CORRESPONDING FIELDS INTO TABLE` addition appends the selected data to the end of the table without deleting existing -table entries. The `INTO CORRESPONDING FIELDS OF TABLE` addition adds lines and deletes existing table entries. -``` abap -SELECT FROM dbtab2 - FIELDS * - WHERE ... - APPENDING CORRESPONDING FIELDS OF TABLE @itab. - -SELECT FROM dbtab2 - FIELDS * - WHERE ... - INTO CORRESPONDING FIELDS OF TABLE @itab. -``` - -Combining data from multiple database tables into one internal table using an [inner -join](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abeninner_join_glosry.htm "Glossary Entry"). -The following example uses the [`INNER JOIN`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapselect_join.htm) addition. Note that the field list includes fields from both tables. The fields are referred to using `~`. -``` abap -SELECT db1~comp1, db1~comp2, db2~comp_abc, db2~comp_xyz ... - FROM db1 - INNER JOIN db2 ON db1~comp1 = db2~comp1 - INTO TABLE @DATA(it_join_result). -``` - -Populating an internal table from a database table using -[subqueries](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abensubquery_glosry.htm "Glossary Entry"). -The following two examples populate an internal table from a database table. In the first example, a subquery is specified in the -`WHERE` clause with the `NOT IN` addition. It checks whether a value matches a value in a set of values -specified in parentheses. The second example populates an internal table depending on data in another table. A subquery with the `EXISTS` addition is specified in -the `WHERE` clause. In this -case, the result of the subquery, which is another -`SELECT` statement, is checked to see if an entry exists in -a table based on the specified conditions. - -``` abap -SELECT comp1, comp2, ... - FROM dbtab - WHERE comp1 NOT IN ( a, b, c ... ) - INTO TABLE @DATA(it_subquery_result1). - -SELECT comp1, comp2, ... - FROM db1 - WHERE EXISTS ( SELECT 'X' FROM db2 - WHERE comp1 = db1~comp1 ) - INTO TABLE @DATA(it_subquery_result2). -``` - -Populating an internal table from a table based on the existence of data in -another table using the [`FOR ALL ENTRIES`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenwhere_all_entries.htm) addition. - -> **💡 Note**
-> Make sure that the internal table you are reading from is not initial. Therefore, it is recommended that you use a subquery as shown above: `... ( SELECT ... FROM ... WHERE ... ) ...`. - -``` abap -IF itab IS NOT INITIAL. - - SELECT dbtab~comp1, dbtab~comp2, ... - FROM dbtab - FOR ALL ENTRIES IN @itab - WHERE comp1 = @itab-comp1 - INTO TABLE @DATA(it_select_result). - -ENDIF. -``` - -

⬆️ back to top

- -### SELECT Queries with Internal Tables as Data Sources - -- You can use internal tables as data sources in `SELECT` statements. - - ``` abap - SELECT comp1, comp2, ... - FROM @itab AS it_alias - WHERE ... - INTO TABLE @DATA(itab_sel). - ``` -- Internal tables are specified as [host variables](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenhost_variable_glosry.htm) prefixed by `@` and provided with an alias name. -- Deep and nested structured types are not allowed. Structured types cannot include strings, reference types, or internal tables. Exception: The type `string` is allowed if it is declared using a reference to the built-in dictionary type `sstring`. -- When used as data sources in `SELECT` statements, internal tables are treated like DDIC database tables. - - This is the case even if they are not passed to the database. - - They are considered as client-independent tables, and the first column is not considered as a client column. - - The ABAP types of the columns are mapped to appropriate DDIC built-in types. -- Using `SELECT` statements with internal tables has significant advantages: - - You can leverage the extensive functionalities that ABAP SQL provides with `SELECT` statements, such as aggregate expressions. - - They can serve as alternatives to `READ TABLE` or `LOOP AT` statements, provided the data can be processed on the AS ABAP by the ABAP SQL engine and the SQL functionality surpasses the standard functionality of these ABAP statements. - -Notes and restrictions: - -- In ABAP, database data is buffered in a [table buffer](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abentable_buffer_glosry.htm) (internally, this happens in internal tables in the [shared memory](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenshared_memory_glosry.htm) of the ABAP server). -- During read access, it is checked if the data is in the buffer, and if so, a read happens directly from there. If not, the data is first loaded into the buffer. -- The [ABAP SQL engine](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenabap_sql_engine_glosry.htm) is involved in the read process. It processes reads and is used when tabular data is read (with a `SELECT` statement). This includes both buffered data from database tables in the table buffer and also internal tables of the current internal session. -- Which means the ABAP SQL engine processes queries located on the AS ABAP, ABAP SQL is executed in the said buffer on the AS ABAP, not directly on the database. -- However, if a `SELECT` statement includes elements the ABAP SQL engine cannot handle in case of internal tables, the internal table data transfers to a temporary database table for query execution. -- Yet, only the data of one internal table can be transferred to the database. Thus, if a query involves multiple internal tables, it can only be executed if the ABAP SQL engine can manage it. This means that if data from more than one internal table must be transferred to the database, the query will not function. Similarly, joins of database tables and internal tables can only specify one internal table whose data can be passed to the database. -- If the compiler detects a statement the ABAP SQL engine cannot process, a syntax warning appears. To suppress this warning, use the pragma `##itab_db_select`. -- As mentioned, internal tables are treated like DDIC database tables. For example, if the internal table specifies a key that is not specified at the beginning of the line type, you cannot use `SELECT` to retrieve data from the table. - ```abap - TYPES: BEGIN OF s, - comp1 TYPE i, - comp2 TYPE i, - comp3 TYPE i, - END OF s. - DATA itab TYPE TABLE OF s WITH KEY comp3. - "SELECT SINGLE * FROM @itab AS tab INTO @DATA(line). - ``` -- Find more information on ... - - the restrictions [here](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abensql_engine_restr.htm). - - the various ABAP SQL functionalities in the ABAP Keyword Documentation and in the [ABAP SQL cheat sheet](03_ABAP_SQL.md). The following code snippets cover a selection. - -The following example explores various `SELECT` queries with internal tables as data sources. To try it out, create a demo class named `zcl_demo_abap` and paste the code into it. After activation, choose *F9* in ADT to execute the class. The example uses objects of the ABAP cheat sheets repository and is set up to display output in the console. - -Example: - -```abap -CLASS zcl_demo_abap DEFINITION - PUBLIC - FINAL - CREATE PUBLIC . - - PUBLIC SECTION. - INTERFACES if_oo_adt_classrun. - PROTECTED SECTION. - PRIVATE SECTION. - -ENDCLASS. - - - -CLASS zcl_demo_abap IMPLEMENTATION. - METHOD if_oo_adt_classrun~main. - - "----------- Exploiting ABAP SQL functionality with internal tables ----------- - - TYPES int_tab_type TYPE TABLE OF i WITH EMPTY KEY. - DATA(itab_a) = VALUE int_tab_type( ( 1 ) ( 32 ) ( 100 ) ( -24 ) ( 17 ) ( 99 ) ). - - "SELECT query with an internal table as data source - "The example uses an aggregate expression. It is statically - "detected that the query cannot be processed by the ABAP SQL - "engine. The data must be passed to the database. Consequently, - "a syntax warning is displayed. It can be suppressed by a pragma. - SELECT MAX( table_line ) AS max_val - FROM @itab_a AS it - INTO @DATA(max_a). - - "100 - SELECT MAX( table_line ) AS max_val ##itab_db_select - FROM @itab_a AS it - INTO @DATA(max_b). - - out->write( max_a ). - out->write( max_b ). - - "Using the LIKE addition in the WHERE clause to extract internal table - "entries matching a specific pattern. - TYPES: BEGIN OF s1, - a TYPE c LENGTH 3, - b TYPE i, - END OF s1, - it_type_1 TYPE TABLE OF s1 WITH EMPTY KEY. - DATA(itab_b) = VALUE it_type_1( ( a = 'abc' b = 1 ) - ( a = 'zbc' b = 2 ) - ( a = 'bde' b = 3 ) - ( a = 'yde' b = 4 ) ). - - SELECT a, b - FROM @itab_b AS it_alias - WHERE a LIKE '%bc' - INTO TABLE @DATA(select_like_result). - -*A B -*abc 1 -*zbc 2 - - out->write( select_like_result ). - - "----------- Using a SELECT loop with an internal table as data source ----------- - - TYPES: BEGIN OF s2, - comp1 TYPE c LENGTH 2, - comp2 TYPE i, - END OF s2, - it_type_2 TYPE TABLE OF s2 WITH EMPTY KEY. - - DATA(itab_c) = VALUE it_type_2( ( comp1 = 'aa' comp2 = 2 ) - ( comp1 = 'zz' comp2 = 9 ) - ( comp1 = 'dd' comp2 = 1 ) - ( comp1 = 'rr' comp2 = 7 ) - ( comp1 = 'tt' comp2 = 5 ) - ( comp1 = 'bb' comp2 = 6 ) ). - - DATA itab_d TYPE int_tab_type. - - "The following SELECT loop specifies an internal table as data source. - "The loop sequence is defined by a sort order. Such a functionality is - "not available with LOOP AT. - SELECT comp2 - FROM @itab_c AS it - ORDER BY comp2 DESCENDING - INTO @DATA(wa). - INSERT wa INTO TABLE itab_d. - ENDSELECT. - -*9 -*7 -*6 -*5 -*2 -*1 - - out->write( itab_d ). - - "------------------- Joins with internal tables ------------------- - - TYPES: BEGIN OF s3, - a TYPE c LENGTH 3, - b TYPE c LENGTH 3, - c TYPE i, - END OF s3, - it_type_3 TYPE TABLE OF s3 WITH EMPTY KEY. - - DATA(itab_e) = VALUE it_type_3( ( a = 'aaa' b = 'bbb' c = 1 ) - ( a = 'ccc' b = 'ddd' c = 1 ) - ( a = 'eee' b = 'fff' c = 2 ) ). - - DATA(itab_f) = VALUE it_type_3( ( a = 'ggg' b = 'hhh' c = 1 ) - ( a = 'iii' b = 'jjj' c = 1 ) - ( a = 'kkk' b = 'lll' c = 3 ) ). - - "No syntax warning. The internal tables can be processed by the - "ABAP SQL engine. - SELECT it_alias1~a, it_alias2~b - FROM @itab_e AS it_alias1 - INNER JOIN @itab_f AS it_alias2 ON it_alias1~c = it_alias2~c - INTO TABLE @DATA(itab_g). - -*A B -*aaa hhh -*aaa jjj -*ccc hhh -*ccc jjj - - out->write( itab_g ). - - "Join with a database table and an internal table - - "Preparing a demo database table and an internal table - DELETE FROM zdemo_abap_tab1. - INSERT zdemo_abap_tab1 FROM TABLE @( VALUE #( ( key_field = 1 char1 = 'aaa' ) - ( key_field = 2 char1 = 'bbb' ) - ( key_field = 3 char1 = 'ccc' ) ) ). - - TYPES it_type_4 TYPE TABLE OF zdemo_abap_tab1 WITH EMPTY KEY. - DATA(itab_h) = VALUE it_type_4( ( key_field = 1 char2 = 'zzz' ) - ( key_field = 2 char2 = 'yyy' ) ). - - SELECT db~key_field, db~char1, it~char2 - FROM zdemo_abap_tab1 AS db - INNER JOIN @itab_h AS it ON it~key_field = db~key_field - INTO TABLE @DATA(itab_i). - -*KEY_FIELD CHAR1 CHAR2 -*1 aaa zzz -*2 bbb yyy - - out->write( itab_i ). - ENDMETHOD. -ENDCLASS. -``` - -

⬆️ back to top

- - -### Restrictions Regarding Selecting from Internal Tables - -- This excursion is intended to underscore the restrictions mentioned above and in the [documentation](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abensql_engine_restr.htm) in more detail when selecting from internal tables. -- Components having deep types cannot be included, for example, in the `SELECT` list or `WHERE` clause. -- Among the non-allowed types of internal table components are strings (as they are deep types) and `utclong`. -- Note that only those fields are checked (and sent to the database) that are actually used (as shown in the example below). -- However, the type string is allowed if it is declared using the built-in dictionary type `sstring` (for example, a component typed with a [data element](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abendata_element_glosry.htm) or a [CDS simple type](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abencds_simple_type_glosry.htm) that uses `sstring`). - -The following example demonstrates various `SELECT` statements. A demo internal table has a component that is typed with a CDS simple type, which can be created as follows: -- In ADT, right-click your pacakage, and choose *New -> Other Repository Object* -- Insert *type* and select *Type* under *Core Data Services*. -- Choose *Next* and provide a name (e.g. `zdemo_abap_string`) and a description. -- Choose *Finish*. -- Find more information on CDS simple types [here](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abencds_simple_types.htm). - -The code of the CDS simple type may look as follows: - -```abap -@EndUserText.label: 'String type' -define type zdemo_abap_string: abap.sstring( 1333 ); -``` - -Commented code example: - -```abap -"------ Internal table having a component of type string ------ -"Creating and populating an internal table that includes a component that is -"typed with type string -TYPES: BEGIN OF s1, - comp1 TYPE i, - comp2 TYPE c LENGTH 3, - comp3 TYPE string, - END OF s1, - tab_type_1 TYPE TABLE OF s1 WITH EMPTY KEY. -DATA(itab1) = VALUE tab_type_1( ( comp1 = 1 comp2 = 'aaa' comp3 = `ABAP` ) ). - -"Columns of type string cannot be used in SELECT statements that -"select from internal tables (* selects all fields). Therefore, the -"following statements are commented out. - -"SELECT SINGLE * FROM @itab1 AS it WHERE comp1 = 1 INTO @DATA(res1). -"SELECT SINGLE comp1 FROM @itab1 AS it where comp3 = `ABAP` INTO @DATA(res2). -"SELECT SINGLE comp3 FROM @itab1 AS it where comp1 = 1 INTO @DATA(res3). - -"However, the following statements work. No component of type string is involved. -SELECT SINGLE comp1 FROM @itab1 AS it WHERE comp2 = 'aaa' INTO @DATA(res4). -SELECT SINGLE comp1, comp2 FROM @itab1 AS it INTO @DATA(res5). - -"--- Internal table having a component typed with a CDS simple type (sstring) --- -"Creating and populating an internal table that includes a component that is typed -"with a CDS simple type (sstring). Note: Built-in DDIC types such as sstring cannot -"directly be used in ABAP statements, except for typed literals. -TYPES: BEGIN OF s2, - comp1 TYPE i, - comp2 TYPE c LENGTH 3, - comp3 TYPE zdemo_abap_string, - END OF s2, - tab_type_2 TYPE TABLE OF s2 WITH EMPTY KEY. -DATA(itab2) = VALUE tab_type_2( ( comp1 = 1 comp2 = 'aaa' comp3 = `ABAP` ) ). - -"Unlike above, the following SELECT statements are possible -SELECT SINGLE * FROM @itab2 AS it WHERE comp1 = 1 INTO @DATA(res6). -SELECT SINGLE comp1 FROM @itab2 AS it WHERE comp3 = `ABAP` INTO @DATA(res7). -SELECT SINGLE comp1, comp3 FROM @itab2 AS it WHERE comp2 = 'aaa' AND comp3 = `ABAP` INTO @DATA(res8). -"Note: `ABAP` represents a literal of type string. When specifying it here -"like it is specified above, there is an implicit conversion. The following -"example uses a typed literal. -SELECT SINGLE comp1, comp2, comp3 FROM @itab2 AS it WHERE comp3 = sstring`ABAP` INTO @DATA(res9). -``` - -

⬆️ back to top

- -### Excursion: Joining/Merging Internal Tables into Internal Tables - -The following code snippets demonstrate joining/merging the content of two simple internal tables into another table. There may be several ways to achieve this. Here, the intention is to give an idea and, in particular, to emphasize SQL functionalities also available for internal tables (note the restrictions mentioned above and in the documentation). - -Assumptions: -- The target table is either created inline or exists and includes components from the source tables or components that can be mapped. -- One or more components are common between the source tables to perform a join or merge the table content. - -The code snippet shows a selection of syntax options and includes the following statements: -- Joins with `SELECT` (`INNER JOIN`, `LEFT OUTER JOIN`, CTE) -- Loops with `LOOP AT` statements, `FOR` loops using the `VALUE` and `REDUCE` operators - -```abap -"Creating two internal tables whose content will be joined. The shared -"value is represented by the key1 and key2 components. -"Sorted tables are used in the example (having key1/key2 as unique keys) -"to have unique values to perform joins. -TYPES: BEGIN OF s1, - key1 TYPE i, - a TYPE c LENGTH 1, - b TYPE c LENGTH 1, - c TYPE c LENGTH 1, - END OF s1, - tab_type1 TYPE SORTED TABLE OF s1 WITH UNIQUE KEY key1, - BEGIN OF s2, - key2 TYPE i, - d TYPE c LENGTH 1, - e TYPE c LENGTH 1, - END OF s2, - tab_type2 TYPE SORTED TABLE OF s2 WITH UNIQUE KEY key2. - -"Populating demo internal tables -DATA(itab1) = VALUE tab_type1( ( key1 = 1 a = 'a' b = 'b' c = 'c' ) - ( key1 = 2 a = 'd' b = 'e' c = 'f' ) - ( key1 = 3 a = 'g' b = 'h' c = 'i' ) ). - -DATA(itab2) = VALUE tab_type2( ( key2 = 1 d = 'j' e = 'k' ) - ( key2 = 2 d = 'l' e = 'm' ) ). - -"SELECT statement, inner join -"Note: With the inner join, the target table contains all -"combinations of rows for whose columns the join condition -"is true. -SELECT a~key1, a~a, a~b, b~d, b~e - FROM @itab1 AS a - INNER JOIN @itab2 AS b ON a~key1 = b~key2 - INTO TABLE @DATA(itab3). - -*Result -*KEY1 A B D E -*1 a b j k -*2 d e l m - -"SELECT statement, left outer join -"In contrast to the inner join above, the target table here -"also contains the table row of the first table for which -"no equivalent row exists in the second table. -SELECT a~key1, a~a, a~b, b~d, b~e - FROM @itab1 AS a - LEFT OUTER JOIN @itab2 AS b ON a~key1 = b~key2 - INTO TABLE @DATA(itab4). - -*Result -*KEY1 A B D E -*1 a b j k -*2 d e l m -*3 g h - -"------------------------ NOTE ----------------------------------- -"--- The following statements produce the same result as the ----- -"--- previous example (itab4). ----------------------------------- -"----------------------------------------------------------------- - -"Common table expression -WITH +it1 AS ( SELECT a~key1, a~a, a~b FROM @itab1 AS a ), - +it2 AS ( SELECT b~key2, b~d, b~e FROM @itab2 AS b ) -SELECT +it1~key1, +it1~a, +it1~b, +it2~d, +it2~e FROM +it1 LEFT JOIN +it2 ON +it1~key1 = +it2~key2 -INTO TABLE @DATA(itab5). - -"LOOP statements -"Using the CORRESPONDING operator to assign identically named components, -"BASE retains existing content -"The assignment with CORRESPONDING ... BASE ... includes a table expression -"in which table lines are read and inserted based on the key mapping. With the -"OPTIONAL addition, errors can be avoided if a line does not exist. -DATA itab6 LIKE itab4. -LOOP AT itab1 INTO DATA(wa1). - INSERT CORRESPONDING #( wa1 ) INTO TABLE itab6 REFERENCE INTO DATA(ref). - ref->* = CORRESPONDING #( BASE ( ref->* ) VALUE #( itab2[ key2 = ref->key1 ] OPTIONAL ) ). -ENDLOOP. -"Assume the second table's shared component was also key1. In the second CORRESPONDING -"you could then work with the EXCEPT addition to not overwrite the identically named -"component. - -"Example similar to the previous one -"Also here, a table expression is used to read a line from -"the second internal table. The INSERT statement (without -"CORRESPONDING) includes the concrete value assignments -"with the VALUE operator. -DATA itab7 LIKE itab4. -LOOP AT itab1 INTO DATA(wa2). - DATA(line) = VALUE #( itab2[ key2 = wa2-key1 ] OPTIONAL ). - - INSERT VALUE #( key1 = wa2-key1 - a = wa2-a - b = wa2-b - d = line-d - e = line-e ) INTO TABLE itab7. -ENDLOOP. - -"Example using a FOR loop with the VALUE operator -TYPES tt_type3 LIKE itab4. -DATA(itab8) = VALUE tt_type3( FOR wa3 IN itab1 - ( key1 = wa3-key1 - a = wa3-a - b = wa3-b - d = VALUE #( itab2[ key2 = wa3-key1 ]-d OPTIONAL ) - e = VALUE #( itab2[ key2 = wa3-key1 ]-e OPTIONAL ) ) ). - -"Similar example that includes a LET expression -DATA(itab9) = VALUE tt_type3( FOR wa4 IN itab1 - LET tab_line = VALUE #( itab2[ key2 = wa4-key1 ] OPTIONAL ) IN - ( key1 = wa4-key1 - a = wa4-a - b = wa4-b - d = tab_line-d - e = tab_line-e ) ). - -"Example using a FOR loop with the REDUCE operator and LET -DATA(itab10) = REDUCE tt_type3( INIT tab = VALUE #( ) - FOR wa5 IN itab1 - LET tableline = VALUE #( itab2[ key2 = wa5-key1 ] OPTIONAL ) IN - NEXT tab = VALUE #( BASE tab - ( key1 = wa5-key1 - a = wa5-a - b = wa5-b - d = tableline-d - e = tableline-e ) ) ). -``` - - -

⬆️ back to top

- -## Sorting Internal Tables - -- Sorted tables are stored in the memory in an automatically sorted - order, hence, they cannot be sorted explicitly with - [`SORT`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapsort_itab.htm). -- For standard and hashed tables, the order can be changed. -- When using `SORT` statements, the sort order is derived either - by the primary table key (Note: Secondary keys - cannot be used for the sorting.) or by explicitly specifying the - fields to be sorted by. -- Explicit specification is the recommended way because it is - easier to understand and can prevent unwanted sorting results, - especially with tables with standard key. -- You can also sort dynamically. For more information, refer to the [Dynamic Programming](06_Dynamic_Programming.md) cheat sheet. - - - - - - - - - - - - - - - -
Subject Details/Code Snippet
Sorting by primary table key - -``` abap -"Implicit sorting by primary table key and in ascending order by default -SORT itab. - -"Optional additions to determine the sort order -"As mentioned above, ASCENDING is used implicitly. Here, specifying it explicitly. -SORT itab ASCENDING. -SORT itab DESCENDING. -``` - -The effect of sorting can have an unexpected result if you use the simple form of the statement and do not explicitly specify the keys. If an internal table has a structured line type and (perhaps inadvertently) the standard key as the primary table key, that is, all character-like and byte-like components make up the primary table key, all these components are taken into account when the table is sorted. -``` abap -"Is basically the same as it2 -DATA it1 TYPE TABLE OF zdemo_abap_fli. - -DATA it2 TYPE STANDARD TABLE OF zdemo_abap_fli WITH DEFAULT KEY. - -"Respecting the standard key when sorting -SORT it1. -``` -Plus: Suppose there are only elementary numeric components in an internal table with a structured line type. In this case, sorting has no effect because the primary table key is considered empty. This is also applies to tables declared with `EMPTY KEY`. - -
Sorting by explicitly specifying components - -You can sort by any component of the internal table. It is also possible to specify the sort order -(even component-wise). Explicitly specifying the components has the advantage that your code is easier to understand and you can avoid unexpected results if you accidentally use `SORT` without the `BY` addition on empty and standard table keys. - -
- -``` abap -DATA it3 TYPE TABLE OF struc WITH NON-UNIQUE KEY a. - -"Sorting by primary table key a -SORT itab. - -"Specifying the component to sort for; here, it is the same as the key; -"this way, the sorting is easier to understand -SORT itab BY a. - -"Syntax showing multiple component sorting with component-wise sort order -SORT itab BY a b ASCENDING c DESCENDING. - -"Sorting respecting the entire line (e. g. in the context of tables with -"empty or standard keys) -SORT itab BY table_line. -``` - -
- -

⬆️ back to top

- ## Modifying Internal Table Content As mentioned above, you can modify the content of internal table lines directly in the context of `READ TABLE` and `LOOP AT` statements using field symbols and data reference variables. You can also use table expressions for direct modification (as also covered in section [Table Expressions](#table-expressions)). Note that the key fields of the primary table key of sorted and hashed tables are always read-only. If you try to modify a key field, a runtime error occurs. However, this is not checked until runtime. @@ -4819,14 +4083,20 @@ it_st = VALUE #( ( comp1 = 1 comp2 = `AAAAAA` comp3 = 'bbb' ) it_so = it_st. it_ha = it_st. -"---- Modifying internal table content by changing the ---- -"---- content of READ TABLE statement target areas -------- +*&---------------------------------------------------------------------* +*& Modifying internal table content by changing the content of READ +*& TABLE statement target areas +*&---------------------------------------------------------------------* + "Reading table line into a target area READ TABLE it_st INTO DATA(wa) INDEX 1. READ TABLE it_so ASSIGNING FIELD-SYMBOL() INDEX 2. READ TABLE it_ha REFERENCE INTO DATA(dref) WITH TABLE KEY comp1 = 3. "No reading by index in case of hashed tables -"------ Modification examples ------- +*&---------------------------------------------------------------------* +*& Modification examples +*&---------------------------------------------------------------------* + "Modifying all non-key components using the VALUE operator and "the BASE addition = VALUE #( BASE comp2 = `IIIIII` comp3 = 'jjj' ). @@ -4868,7 +4138,9 @@ dref->comp2 = `VVVVVV`. "dereferencing and component selector operators in the following way. dref->*-comp3 = 'www'. -"---- Modifying internal table content using table expressions ----- +*&---------------------------------------------------------------------* +*& Modifying internal table content using table expressions +*&---------------------------------------------------------------------* "Changing the entire table line of a standard table "In standard tables, the key value change is allowed. @@ -4890,14 +4162,20 @@ it_ha[ comp2 = `CCCCCC` ]-comp2 = `B2`. "it_ha[ comp2 = `AAAAAA` ]-comp1 = `C3`. it_st[ 1 ]-comp1 = 99. -"---- Modifying table content in all table rows in a loop ---- +*&---------------------------------------------------------------------* +*& Modifying table content in all table rows in a loop +*&---------------------------------------------------------------------* + "For more syntax options regarding loops, check the section above. "Target area: field symbol LOOP AT it_st ASSIGNING FIELD-SYMBOL(). -comp2 = sy-tabix. ENDLOOP. -"---- Modifying table content restricting the rows that are looped across ---- +*&---------------------------------------------------------------------* +*& Modifying table content restricting the rows that are looped across +*&---------------------------------------------------------------------* + "Target area: data reference variable LOOP AT it_st reference into data(lo) FROM 2 TO 3. lo->comp3 = sy-tabix. @@ -4966,7 +4244,9 @@ MODIFY it FROM line TRANSPORTING b c WHERE a < 5. You can use [`DELETE`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapdelete_itab.htm) statements to delete single and multiple lines in internal tables. The following additions can be used: `USING KEY` (for specifying a table key), `FROM`/`TO` (for specifying row ranges), `STEP` (for specifying the step size), and `WHERE` (for specifying conditions). ``` abap -"-------------- Deleting via index -------------- +*&---------------------------------------------------------------------* +*& Deleting via index +*&---------------------------------------------------------------------* "Example: The first line in the table is deleted. DELETE it INDEX 1. @@ -4980,7 +4260,9 @@ DELETE it INDEX 1 USING KEY primary_key. "Deleting an index range; FROM or TO alone can also be specified DELETE it FROM 2 TO 5. -"-------------- Deleting via keys -------------- +*&---------------------------------------------------------------------* +*& Deleting via keys +*&---------------------------------------------------------------------* "The line must have a compatible type to the tables line type and "include key values. The first found line with the corresponding keys @@ -4999,7 +4281,9 @@ DELETE TABLE it WITH TABLE KEY primary_key COMPONENTS a = 1. DELETE TABLE it_sec WITH TABLE KEY sec_key COMPONENTS ... -"---------- Deleting multiple lines based on a WHERE condition ---------- +*&---------------------------------------------------------------------* +*& Deleting multiple lines based on a WHERE condition +*&---------------------------------------------------------------------* "Specifying the additions USING KEY, FROM, TO is also possible. DELETE it WHERE a < 6. @@ -5016,7 +4300,9 @@ DATA(str_table) = VALUE string_table( ( `abcZ` ) ( `Zdef` ) ( `gZhi` ) DELETE str_table WHERE table_line CP `Z*`. "Result: abcZ / gZhi / pqrZ -"---------- Deleting the current line inside a LOOP statement ---------- +*&---------------------------------------------------------------------* +*& Deleting the current line inside a LOOP statement +*&---------------------------------------------------------------------* "The following example illustrates deleting the current table line "using a DELETE statement within a LOOP statement. Lines with even @@ -5124,6 +4410,182 @@ it_ref = NEW #( ). ```

⬆️ back to top

+## Sorting Internal Tables + +- Sorted tables are stored in the memory in an automatically sorted + order, hence, they cannot be sorted explicitly with + [`SORT`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapsort_itab.htm). +- For standard and hashed tables, the order can be changed. +- When using `SORT` statements, the sort order is derived either + by the primary table key (Note: Secondary keys + cannot be used for the sorting.) or by explicitly specifying the + fields to be sorted by. +- Explicit specification is the recommended way because it is + easier to understand and can prevent unwanted sorting results, + especially with tables with standard key. +- Note that sorting is unstable by default concerning preserving the order of table lines with identical sort keys. Sorting results can vary if the table is sorted multiple times. +- You can also sort dynamically. For more information, refer to the [Dynamic Programming](06_Dynamic_Programming.md) cheat sheet. + + + + + + + + + + + + + + + + + + + + + +
Subject Details/Code Snippet
Sorting by primary table key + +``` abap +"Implicit sorting by primary table key and in ascending order by default +SORT itab. + +"Optional additions to determine the sort order +"As mentioned above, ASCENDING is used implicitly. Here, specifying it explicitly. +SORT itab ASCENDING. +SORT itab DESCENDING. +``` + +The effect of sorting can have an unexpected result if you use the simple form of the statement and do not explicitly specify the keys. If an internal table has a structured line type and (perhaps inadvertently) the standard key as the primary table key, that is, all character-like and byte-like components make up the primary table key, all these components are taken into account when the table is sorted. +``` abap +"Is basically the same as it2 +DATA it1 TYPE TABLE OF zdemo_abap_fli. + +DATA it2 TYPE STANDARD TABLE OF zdemo_abap_fli WITH DEFAULT KEY. + +"Respecting the standard key when sorting +SORT it1. +``` +Plus: Suppose there are only elementary numeric components in an internal table with a structured line type. In this case, sorting has no effect because the primary table key is considered empty. This is also applies to tables declared with `EMPTY KEY`. + +
Sorting by explicitly specifying components + +You can sort by any component of the internal table. It is also possible to specify the sort order +(even component-wise). Explicitly specifying the components has the advantage that your code is easier to understand and you can avoid unexpected results if you accidentally use `SORT` without the `BY` addition on empty and standard table keys. + +
+ +``` abap +DATA it3 TYPE TABLE OF struc WITH NON-UNIQUE KEY a. + +"Sorting by primary table key a +SORT itab. + +"Specifying the component to sort for; here, it is the same as the key; +"this way, the sorting is easier to understand +SORT itab BY a. + +"Syntax showing multiple component sorting with component-wise sort order +SORT itab BY a b ASCENDING c DESCENDING. + +"Sorting respecting the entire line (e. g. in the context of tables with +"empty or standard keys) +SORT itab BY table_line. +``` + +
Stable sorting + +By default, the sorting is unstable concerning preserving the order of table lines with identical sort keys. To ensure a stable sorting with preserving the order of table lines with identical +sort keys, you can use the `STABLE` addition.

+This code example explores the difference in sorting results when using `STABLE` versus not using it with the `SORT` statement. A `SELECT` statement retrieves data from an internal table, specifying an `ORDER BY` clause for two columns. `SORT` statements sort the internal table. Using `STABLE` demonstrates that the relative order of the columns specified in the `ORDER BY` clause is preserved. Without `STABLE`, this relative order is not necessarily maintained. The `CL_ABAP_DIFF` class is used to compare the internal table content. + +
+ +``` abap +CLASS zcl_demo_abap DEFINITION + PUBLIC + FINAL + CREATE PUBLIC . + + PUBLIC SECTION. + INTERFACES if_oo_adt_classrun. + PROTECTED SECTION. + PRIVATE SECTION. +ENDCLASS. + + +CLASS zcl_demo_abap IMPLEMENTATION. + METHOD if_oo_adt_classrun~main. + TYPES: BEGIN OF demo_flights, + carrid TYPE c LENGTH 3, + connid TYPE n LENGTH 4, + cityfrom TYPE c LENGTH 20, + cityto TYPE c LENGTH 20, + END OF demo_flights, + ty_flights TYPE TABLE OF demo_flights WITH EMPTY KEY. + + DATA(itab) = VALUE ty_flights( + ( carrid = 'AA' connid = '0017' cityfrom = 'NEW YORK' cityto = 'SAN FRANCISCO' ) + ( carrid = 'AA' connid = '0064' cityfrom = 'SAN FRANCISCO' cityto = 'NEW YORK' ) + ( carrid = 'AZ' connid = '0555' cityfrom = 'ROME' cityto = 'FRANKFURT' ) + ( carrid = 'AZ' connid = '0788' cityfrom = 'ROME' cityto = 'TOKYO' ) + ( carrid = 'AZ' connid = '0789' cityfrom = 'TOKYO' cityto = 'ROME' ) + ( carrid = 'AZ' connid = '0790' cityfrom = 'ROME' cityto = 'OSAKA' ) + ( carrid = 'DL' connid = '0106' cityfrom = 'NEW YORK' cityto = 'FRANKFURT' ) + ( carrid = 'DL' connid = '1699' cityfrom = 'NEW YORK' cityto = 'SAN FRANCISCO' ) + ( carrid = 'DL' connid = '1984' cityfrom = 'SAN FRANCISCO' cityto = 'NEW YORK' ) + ( carrid = 'JL' connid = '0407' cityfrom = 'TOKYO' cityto = 'FRANKFURT' ) + ( carrid = 'JL' connid = '0408' cityfrom = 'FRANKFURT' cityto = 'TOKYO' ) + ( carrid = 'LH' connid = '0400' cityfrom = 'FRANKFURT' cityto = 'NEW YORK' ) + ( carrid = 'LH' connid = '0401' cityfrom = 'NEW YORK' cityto = 'FRANKFURT' ) + ( carrid = 'LH' connid = '0402' cityfrom = 'FRANKFURT' cityto = 'NEW YORK' ) + ( carrid = 'LH' connid = '2402' cityfrom = 'FRANKFURT' cityto = 'BERLIN' ) + ( carrid = 'LH' connid = '2407' cityfrom = 'BERLIN' cityto = 'FRANKFURT' ) + ( carrid = 'QF' connid = '0005' cityfrom = 'SINGAPORE' cityto = 'FRANKFURT' ) + ( carrid = 'QF' connid = '0006' cityfrom = 'FRANKFURT' cityto = 'SINGAPORE' ) + ( carrid = 'SQ' connid = '0988' cityfrom = 'SINGAPORE' cityto = 'TOKYO' ) + ( carrid = 'UA' connid = '0941' cityfrom = 'FRANKFURT' cityto = 'SAN FRANCISCO' ) + ( carrid = 'UA' connid = '3504' cityfrom = 'SAN FRANCISCO' cityto = 'FRANKFURT' ) + ( carrid = 'UA' connid = '3516' cityfrom = 'NEW YORK' cityto = 'FRANKFURT' ) + ( carrid = 'UA' connid = '3517' cityfrom = 'FRANKFURT' cityto = 'NEW YORK' ) ). + + SELECT carrid, connid, cityfrom, cityto + FROM @itab AS tab + ORDER BY carrid, connid + INTO TABLE @DATA(flights). + + DATA(fl_stable) = flights. + DATA(fl_non_stable) = flights. + + SORT fl_stable STABLE BY cityfrom cityto. + SORT fl_non_stable BY cityfrom cityto. + + DATA is_identical TYPE abap_boolean. + DATA(comparison) = cl_abap_diff=>create( ). + TRY. + DATA(comp_result) = comparison->diff( EXPORTING target = fl_stable + source = fl_non_stable + IMPORTING flag_identical = is_identical ). + IF is_identical = abap_true. + out->write( `Comparison result: Identical` ). + ELSE. + out->write( `Comparison result: Not identical` ). + ENDIF. + CATCH cx_abap_diff INTO DATA(error). + out->write( error->get_text( ) ). + ENDTRY. + out->write( comp_result ). + ENDMETHOD. +ENDCLASS. +``` + +
+ +

⬆️ back to top

+ + ## Grouping Internal Tables To group internal tables, there are additions for `LOOP AT` statements. @@ -5316,7 +4778,6 @@ ENDCLASS.

⬆️ back to top

- ## Collecting Values - You can use `COLLECT` statements, for example, to add the values of numeric components to the corresponding values in an internal table. @@ -5359,6 +4820,719 @@ ENDLOOP. ASSERT seats_tab_loop_grp = seats_tab_col. ``` +

⬆️ back to top

+ +## Getting Information about Internal Tables, Table Lines, Table Types + +### Checking the Existence of a Line in an Internal Table + +This is relevant if you are not interested in the content of a table +line, but only want to find out whether a line exists that matches to the +index or key specifications. To do this, use a [`READ TABLE`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapread_table.htm) +statement with the `TRANSPORTING NO FIELDS` addition. The +addition indicates that no actual content is to be read. If the search was +successful and an entry exists, the system field `sy-subrc` is +set to 0. + +A newer way to check the existence of a line is the [predicate +function](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenpredicate_function_glosry.htm "Glossary Entry") +[`line_exists( )`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenline_exists_function.htm). +This function expects a [table +expression](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abentable_expression_glosry.htm "Glossary Entry") as an argument. +See below for more on table expressions. Note that table expressions do not set system fields. +``` abap +"Read using a key +READ TABLE it WITH KEY b = 2 TRANSPORTING NO FIELDS. + +IF sy-subrc = 0. + ... +ENDIF. + +"Read using the index +READ TABLE it INDEX 1 TRANSPORTING NO FIELDS. + +IF sy-subrc = 0. + ... +ENDIF. + +"Read using the key +IF line_exists( it[ b = 2 ] ). + ... +ENDIF. + +"Read using the index +IF line_exists( it[ 1 ] ). + ... +ENDIF. +``` + +

⬆️ back to top

+ +### Checking the Index of a Line in an Internal Table + +If you want to find out about the index of a line in an internal table, you can also make use of the `READ TABLE` statement above. If +the line is found, the system field `sy-tabix` is set to the number of the index. Otherwise, the built-in function +[`line_index( )`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenline_index_function.htm) can be used. It returns the index of the found line or 0 if the line does not exist. + +``` abap +DATA(itab) = VALUE string_table( ( `aaa` ) ( `bbb` ) ). +READ TABLE itab WITH KEY table_line = `bbb` TRANSPORTING NO FIELDS. +"2 +DATA(tabix) = sy-tabix. + +"1 +DATA(idx) = line_index( itab[ table_line = `aaa` ] ). + +"Note: No primary table index with hashed tables +DATA(hashed_tab) = VALUE string_hashed_table( ( `a` ) ( `b` ) ( `c` ) ). +"-1 +DATA(hashed_primary_idx) = line_index( hashed_tab[ table_line = `c` ] ). + +"Index access in hashed tables only using a secondary table index +TYPES: BEGIN OF s, + comp1 TYPE i, + comp2 TYPE i, + END OF s, + ttype TYPE HASHED TABLE OF s WITH UNIQUE KEY comp1 WITH NON-UNIQUE SORTED KEY sk COMPONENTS comp2. + +DATA(hashed_tab2) = VALUE ttype( ( comp1 = 1 comp2 = 10 ) + ( comp1 = 2 comp2 = 8 ) + ( comp1 = 3 comp2 = 9 ) ). + +"3 +DATA(hashed_secondary_idx) = line_index( hashed_tab2[ KEY sk comp2 = 10 ] ). +"1 +hashed_secondary_idx = line_index( hashed_tab2[ KEY sk comp2 = 8 ] ). +``` + +

⬆️ back to top

+ +### Checking How Many Lines Exist in an Internal Table + +`lines( )` is another built-in function that you can use to check how many lines exist in an internal table. It returns an integer value. + +``` abap +DATA(itab) = VALUE string_table( ( `a` ) ( `b` ) ( `c` ) ( `d` ) ( `e` ) ). + +"5 +DATA(number_of_lines) = lines( itab ). + +"Excursion: Finding out the number of lines in a table by specifying concrete +"component values, e.g. you want to find out how many lines exist in the table +"that have the value 1 for comp2 +TYPES: BEGIN OF struct, + comp1 TYPE c LENGTH 3, + comp2 TYPE i, + END OF struct, + tab_type TYPE TABLE OF struct WITH EMPTY KEY. + +DATA(it) = VALUE tab_type( ( comp1 = 'a' comp2 = 1 ) + ( comp1 = 'b' comp2 = 1 ) + ( comp1 = 'c' comp2 = 1 ) + ( comp1 = 'd' comp2 = 2 ) + ( comp1 = 'e' comp2 = 3 ) + ( comp1 = 'f' comp2 = 4 ) + ( comp1 = 'g' comp2 = 5 ) ). + +"7 +DATA(line_num) = lines( it ). + +"Finding out the number of lines in a table by component value, e.g. +"using constructor expressions and specifying a WHERE clause. +"The example creates an new internal table inline using VALUE and a FOR loop, +"specified with a WHERE clause. The lines function is applied to the +"table created inline. +"3 +DATA(line_num_filtered1) = lines( VALUE tab_type( FOR wa IN it WHERE ( comp2 = 1 ) ( wa ) ) ). + +"Using the REDUCE operator +"The example adds 1 to the resulting integer if the comp2 value of the iterated line is greater than 1. +"The lines function is not relevant in the example. +"4 +DATA(line_num_filtered2) = REDUCE i( INIT var = 0 + FOR IN it + WHERE ( comp2 > 1 ) + NEXT var += 1 ). + +"Using the FILTER operator +"Note: The source table must have at least one sorted key or a hash key for accessing. +"If the table does not have such a primary table key, a secondary table key must be available. +TYPES: tab_type_sorted TYPE TABLE OF struct with NON-UNIQUE SORTED KEY sec_key COMPONENTS comp2. +DATA it_sorted type tab_type_sorted. +it_sorted = it. + +"The example creates an new internal table inline using FILTER, +"specified with a WHERE clause. The lines function is applied to the +"table created inline. +"3 +DATA(line_num_filtered3) = lines( FILTER #( it_sorted USING KEY sec_key WHERE comp2 = 1 ) ). +"4 +DATA(line_num_filtered4) = lines( FILTER #( it_sorted USING KEY sec_key WHERE comp2 > 1 ) ). + +"Using LOOP statements +CLEAR number_of_lines. +"No WHERE condition as all lines shall be processed +"7 +LOOP AT it REFERENCE INTO DATA(line). + number_of_lines += 1. +ENDLOOP. + +CLEAR number_of_lines. +"3 +LOOP AT it transporting no fields where comp2 = 1. + number_of_lines += 1. +ENDLOOP. +``` + +

⬆️ back to top

+ +### Getting Table (Type) Information at Runtime + +Using [Runtime Type Identification (RTTI)](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenrun_time_type_identific_glosry.htm "Glossary Entry"), +you can get type information on internal tables and table types at runtime. + +For more information, see the [Dynamic Programming](06_Dynamic_Programming.md) ABAP cheat sheet. + +RTTI example: +```abap +TYPES tab_type TYPE SORTED TABLE OF zdemo_abap_flsch + WITH UNIQUE KEY carrid connid + WITH NON-UNIQUE SORTED KEY sec_key ALIAS sk COMPONENTS countryfr cityto. +DATA itab TYPE tab_type. + +DATA(tdo_d) = cl_abap_typedescr=>describe_by_data( itab ). +"DATA(tdo_d) = cl_abap_typedescr=>describe_by_name( 'TAB_TYPE' ). + +"Cast to get more specific information +DATA(tdo_itab) = CAST cl_abap_tabledescr( cl_abap_typedescr=>describe_by_data( itab ) ). +"DATA(tdo_itab) = CAST cl_abap_tabledescr( tdo_d ). + +DATA(type_category_itab) = tdo_itab->kind. +DATA(relative_name_itab) = tdo_itab->get_relative_name( ). +... "Explore more options by positioning the cursor behind -> and choosing CTRL + Space +DATA(table_kind_itab) = tdo_itab->table_kind. +DATA(table_keys_itab) = tdo_itab->key. +DATA(table_keys_more_details_itab) = tdo_itab->get_keys( ). +DATA(table_has_unique_key_itab) = tdo_itab->has_unique_key. +DATA(table_key_alias_itab) = tdo_itab->get_key_aliases( ). +DATA(line_type_itab) = tdo_itab->get_table_line_type( ). +DATA(table_component_info_itab) = CAST cl_abap_structdescr( tdo_itab->get_table_line_type( ) ). +DATA(table_components_itab) = CAST cl_abap_structdescr( tdo_itab->get_table_line_type( ) )->components. +DATA(table_comps_more_info_itab) = CAST cl_abap_structdescr( tdo_itab->get_table_line_type( ) )->get_components( ). +DATA(applies_to_data_itab) = tdo_itab->applies_to_data( VALUE tab_type( ) ). +``` + +

⬆️ back to top

+ +## Operations with Internal Tables Using ABAP SQL SELECT Statements + +### Internal Tables as Target Data Objects in SELECT Queries + +Adding multiple lines from a database table to an internal table using +[`SELECT`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapselect.htm), +for example, based on a condition. In the case below, the internal table +is created inline. +``` abap +SELECT FROM dbtab + FIELDS comp1, comp2 ... + WHERE ... + INTO TABLE @DATA(itab_sel). +``` + +Adding multiple lines from a database table using `SELECT`, for example, based on a condition when the database table has a line type that is incompatible with the internal table. The `*` character means that all fields are selected. The other examples define specific fields. +The `APPENDING CORRESPONDING FIELDS INTO TABLE` addition appends the selected data to the end of the table without deleting existing +table entries. The `INTO CORRESPONDING FIELDS OF TABLE` addition adds lines and deletes existing table entries. +``` abap +SELECT FROM dbtab2 + FIELDS * + WHERE ... + APPENDING CORRESPONDING FIELDS OF TABLE @itab. + +SELECT FROM dbtab2 + FIELDS * + WHERE ... + INTO CORRESPONDING FIELDS OF TABLE @itab. +``` + +Combining data from multiple database tables into one internal table using an [inner +join](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abeninner_join_glosry.htm "Glossary Entry"). +The following example uses the [`INNER JOIN`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapselect_join.htm) addition. Note that the field list includes fields from both tables. The fields are referred to using `~`. +``` abap +SELECT db1~comp1, db1~comp2, db2~comp_abc, db2~comp_xyz ... + FROM db1 + INNER JOIN db2 ON db1~comp1 = db2~comp1 + INTO TABLE @DATA(it_join_result). +``` + +Populating an internal table from a database table using +[subqueries](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abensubquery_glosry.htm "Glossary Entry"). +The following two examples populate an internal table from a database table. In the first example, a subquery is specified in the +`WHERE` clause with the `NOT IN` addition. It checks whether a value matches a value in a set of values +specified in parentheses. The second example populates an internal table depending on data in another table. A subquery with the `EXISTS` addition is specified in +the `WHERE` clause. In this +case, the result of the subquery, which is another +`SELECT` statement, is checked to see if an entry exists in +a table based on the specified conditions. + +``` abap +SELECT comp1, comp2, ... + FROM dbtab + WHERE comp1 NOT IN ( a, b, c ... ) + INTO TABLE @DATA(it_subquery_result1). + +SELECT comp1, comp2, ... + FROM db1 + WHERE EXISTS ( SELECT 'X' FROM db2 + WHERE comp1 = db1~comp1 ) + INTO TABLE @DATA(it_subquery_result2). +``` + +Populating an internal table from a table based on the existence of data in +another table using the [`FOR ALL ENTRIES`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenwhere_all_entries.htm) addition. + +> **💡 Note**
+> Make sure that the internal table you are reading from is not initial. Therefore, it is recommended that you use a subquery as shown above: `... ( SELECT ... FROM ... WHERE ... ) ...`. + +``` abap +IF itab IS NOT INITIAL. + + SELECT dbtab~comp1, dbtab~comp2, ... + FROM dbtab + FOR ALL ENTRIES IN @itab + WHERE comp1 = @itab-comp1 + INTO TABLE @DATA(it_select_result). + +ENDIF. +``` + +

⬆️ back to top

+ +### SELECT Queries with Internal Tables as Data Sources + +**General rule**: Use `SELECT` with internal tables as a data source only when SQL functionality, such as joins, exceeds ABAP statements. + +**Technical considerations**: +- The [ABAP SQL in-memory engine](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenabap_sql_inmemeng_glosry.htm) manages read access with ABAP SQL `SELECT` statements for tabular data within the memory of an [Application Server ABAP (AS ABAP)](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenas_abap_glosry.htm). The tabular data can include: + - Database table data (such as data from DDIC database tables or CDS entities) buffered in the [table buffer](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenas_abap_glosry.htm) within AS ABAP. Buffering ability is determined by specifications in the artifacts. If the data isn't buffered, the engine can't handle it, and the SQL statement is processed on the database. + - Internal tables present in the current internal session. They are treated like DDIC database tables. ABAP types are mapped to corresponding [built-in DDIC types](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenbuiltin_ddic_type_glosry.htm). +- The ABAP SQL in-memory engine processes data on AS ABAP, not the database server. If a `SELECT` statement using internal tables as data sources includes elements beyond the engine's capability (for example, most subqueries aren't supported; see detailed restrictions [here](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/ABENSQL_ENGINE_RESTR.html)), the internal table content is transferred to a temporary database table before the query executes. Only components involved in the read access are transferred. +- In such cases, the SQL statement runs directly on the database server, not within AS ABAP. If the compiler identifies a statement the ABAP SQL in-memory engine can't handle, a syntax warning occurs. You can suppress this warning using the pragma ##itab_db_select. +- Currently, queries with multiple internal tables can only proceed if the ABAP SQL in-memory engine can manage them on AS ABAP directly. Transferring more than one internal table to the database is currently not supported. +- The result of the ABAP SQL in-memory engine processing is identical to processing the read access directly on the database. + +**Using internal tables as data sources in ABAP SQL SELECT statements**: + +- You must specify internal tables as [host variables](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenhost_variable_glosry.htm) with an `@` prefix and give them an alias. + ``` abap + SELECT comp1, comp2, ... + FROM @itab AS it_alias + WHERE ... + INTO TABLE @DATA(itab_sel). + ``` +- Internal tables are treated like DDIC database tables, which leads to specific behaviors such as: + - They are handled like [client-independent](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenclient_independent_glosry.htm) database tables, and the first table column is not automatically considered a client column. You can change this default behavior using the `DECLARE CLIENT` addition. For example, if the internal table specifies a key that is not specified at the beginning of the line type, you cannot use `SELECT` to retrieve data from the table. + ```abap + TYPES: BEGIN OF s, + comp1 TYPE i, + comp2 TYPE i, + comp3 TYPE i, + END OF s. + DATA itab TYPE TABLE OF s WITH KEY comp3. + "SELECT SINGLE * FROM @itab AS tab INTO @DATA(line). + ``` + - You cannot use deep and nested components of internal tables in `SELECT` statements. + - The type string is supported only if declared as a reference to the built-in dictionary type sstring. +- A key advantage of using `SELECT` statements with internal tables as data sources is the access to ABAP SQL's extensive functionalities, like aggregate expressions. +- They can serve as an alternative to the `READ TABLE` or `LOOP AT` statements if the ABAP SQL in-memory engine can process the data without requiring a database transfer. +- Note the general rule: You should use `SELECT` with internal tables as a data source only when SQL functionality exceeds that of ABAP statements, such as in joins. For tasks achievable with ABAP statements, it's preferable to use them as they are optimized for internal tables and offer better performance. + +**More information**: +- [Restrictions](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abensql_engine_restr.htm). +- See details on the various ABAP SQL functionalities in the ABAP Keyword Documentation and in the [ABAP SQL cheat sheet](03_ABAP_SQL.md). + +The following example explores various `SELECT` queries with internal tables as data sources. To try it out, create a demo class named `zcl_demo_abap` and paste the code into it. After activation, choose *F9* in ADT to execute the class. The example uses objects of the ABAP cheat sheets repository and is set up to display output in the console. + +Example: + +```abap +CLASS zcl_demo_abap DEFINITION + PUBLIC + FINAL + CREATE PUBLIC . + + PUBLIC SECTION. + INTERFACES if_oo_adt_classrun. + PROTECTED SECTION. + PRIVATE SECTION. + +ENDCLASS. + + + +CLASS zcl_demo_abap IMPLEMENTATION. + METHOD if_oo_adt_classrun~main. + + "----------- Exploiting ABAP SQL functionality with internal tables ----------- + + TYPES int_tab_type TYPE TABLE OF i WITH EMPTY KEY. + DATA(itab_a) = VALUE int_tab_type( ( 1 ) ( 32 ) ( 100 ) ( -24 ) ( 17 ) ( 99 ) ). + + "SELECT query with an internal table as data source + "The example uses an aggregate expression. It is statically + "detected that the query cannot be processed by the ABAP SQL + "engine. The data must be passed to the database. Consequently, + "a syntax warning is displayed. It can be suppressed by a pragma. + SELECT MAX( table_line ) AS max_val + FROM @itab_a AS it + INTO @DATA(max_a). + + "100 + SELECT MAX( table_line ) AS max_val ##itab_db_select + FROM @itab_a AS it + INTO @DATA(max_b). + + out->write( max_a ). + out->write( max_b ). + + "Using the LIKE addition in the WHERE clause to extract internal table + "entries matching a specific pattern. + TYPES: BEGIN OF s1, + a TYPE c LENGTH 3, + b TYPE i, + END OF s1, + it_type_1 TYPE TABLE OF s1 WITH EMPTY KEY. + DATA(itab_b) = VALUE it_type_1( ( a = 'abc' b = 1 ) + ( a = 'zbc' b = 2 ) + ( a = 'bde' b = 3 ) + ( a = 'yde' b = 4 ) ). + + SELECT a, b + FROM @itab_b AS it_alias + WHERE a LIKE '%bc' + INTO TABLE @DATA(select_like_result). + +*A B +*abc 1 +*zbc 2 + + out->write( select_like_result ). + + "----------- Using a SELECT loop with an internal table as data source ----------- + + TYPES: BEGIN OF s2, + comp1 TYPE c LENGTH 2, + comp2 TYPE i, + END OF s2, + it_type_2 TYPE TABLE OF s2 WITH EMPTY KEY. + + DATA(itab_c) = VALUE it_type_2( ( comp1 = 'aa' comp2 = 2 ) + ( comp1 = 'zz' comp2 = 9 ) + ( comp1 = 'dd' comp2 = 1 ) + ( comp1 = 'rr' comp2 = 7 ) + ( comp1 = 'tt' comp2 = 5 ) + ( comp1 = 'bb' comp2 = 6 ) ). + + DATA itab_d TYPE int_tab_type. + + "The following SELECT loop specifies an internal table as data source. + "The loop sequence is defined by a sort order. Such a functionality is + "not available with LOOP AT. + SELECT comp2 + FROM @itab_c AS it + ORDER BY comp2 DESCENDING + INTO @DATA(wa). + INSERT wa INTO TABLE itab_d. + ENDSELECT. + +*9 +*7 +*6 +*5 +*2 +*1 + + out->write( itab_d ). + + "------------------- Joins with internal tables ------------------- + + TYPES: BEGIN OF s3, + a TYPE c LENGTH 3, + b TYPE c LENGTH 3, + c TYPE i, + END OF s3, + it_type_3 TYPE TABLE OF s3 WITH EMPTY KEY. + + DATA(itab_e) = VALUE it_type_3( ( a = 'aaa' b = 'bbb' c = 1 ) + ( a = 'ccc' b = 'ddd' c = 1 ) + ( a = 'eee' b = 'fff' c = 2 ) ). + + DATA(itab_f) = VALUE it_type_3( ( a = 'ggg' b = 'hhh' c = 1 ) + ( a = 'iii' b = 'jjj' c = 1 ) + ( a = 'kkk' b = 'lll' c = 3 ) ). + + "No syntax warning. The internal tables can be processed by the + "ABAP SQL engine. + SELECT it_alias1~a, it_alias2~b + FROM @itab_e AS it_alias1 + INNER JOIN @itab_f AS it_alias2 ON it_alias1~c = it_alias2~c + INTO TABLE @DATA(itab_g). + +*A B +*aaa hhh +*aaa jjj +*ccc hhh +*ccc jjj + + out->write( itab_g ). + + "Join with a database table and an internal table + + "Preparing a demo database table and an internal table + DELETE FROM zdemo_abap_tab1. + INSERT zdemo_abap_tab1 FROM TABLE @( VALUE #( ( key_field = 1 char1 = 'aaa' ) + ( key_field = 2 char1 = 'bbb' ) + ( key_field = 3 char1 = 'ccc' ) ) ). + + TYPES it_type_4 TYPE TABLE OF zdemo_abap_tab1 WITH EMPTY KEY. + DATA(itab_h) = VALUE it_type_4( ( key_field = 1 char2 = 'zzz' ) + ( key_field = 2 char2 = 'yyy' ) ). + + SELECT db~key_field, db~char1, it~char2 + FROM zdemo_abap_tab1 AS db + INNER JOIN @itab_h AS it ON it~key_field = db~key_field + INTO TABLE @DATA(itab_i). + +*KEY_FIELD CHAR1 CHAR2 +*1 aaa zzz +*2 bbb yyy + + out->write( itab_i ). + ENDMETHOD. +ENDCLASS. +``` + +

⬆️ back to top

+ + +#### Restrictions Regarding Internal Tables as Data Sources in ABAP SQL SELECT Statements + +- This excursion is intended to underscore the restrictions mentioned above and in the [documentation](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abensql_engine_restr.htm) in more detail when selecting from internal tables. +- Components having deep types cannot be included, for example, in the `SELECT` list or `WHERE` clause. +- Among the non-allowed types of internal table components are strings (as they are deep types) and `utclong`. +- Note that only those fields are checked (and sent to the database) that are actually used (as shown in the example below). +- However, the type string is allowed if it is declared using the built-in dictionary type `sstring` (for example, a component typed with a [data element](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abendata_element_glosry.htm) or a [CDS simple type](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abencds_simple_type_glosry.htm) that uses `sstring`). + +The following example demonstrates various `SELECT` statements. A demo internal table has a component that is typed with a CDS simple type, which can be created as follows: +- In ADT, right-click your pacakage, and choose *New -> Other Repository Object* +- Insert *type* and select *Type* under *Core Data Services*. +- Choose *Next* and provide a name (e.g. `zdemo_abap_string`) and a description. +- Choose *Finish*. +- Find more information on CDS simple types [here](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abencds_simple_types.htm). + +The code of the CDS simple type may look as follows: + +```abap +@EndUserText.label: 'String type' +define type zdemo_abap_string: abap.sstring( 1333 ); +``` + +Commented code example: + +```abap +*&---------------------------------------------------------------------* +*& Internal table having a component of type string +*&---------------------------------------------------------------------* + +"Creating and populating an internal table that includes a component that is +"typed with type string +TYPES: BEGIN OF s1, + comp1 TYPE i, + comp2 TYPE c LENGTH 3, + comp3 TYPE string, + END OF s1, + tab_type_1 TYPE TABLE OF s1 WITH EMPTY KEY. +DATA(itab1) = VALUE tab_type_1( ( comp1 = 1 comp2 = 'aaa' comp3 = `ABAP` ) ). + +"Columns of type string cannot be used in SELECT statements that +"select from internal tables (* selects all fields). Therefore, the +"following statements are commented out. + +"SELECT SINGLE * FROM @itab1 AS it WHERE comp1 = 1 INTO @DATA(res1). +"SELECT SINGLE comp1 FROM @itab1 AS it where comp3 = `ABAP` INTO @DATA(res2). +"SELECT SINGLE comp3 FROM @itab1 AS it where comp1 = 1 INTO @DATA(res3). + +"However, the following statements work. No component of type string is involved. +SELECT SINGLE comp1 FROM @itab1 AS it WHERE comp2 = 'aaa' INTO @DATA(res4). +SELECT SINGLE comp1, comp2 FROM @itab1 AS it INTO @DATA(res5). + +*&---------------------------------------------------------------------* +*& Internal table having a component typed with a CDS simple type (sstring) +*&---------------------------------------------------------------------* + +"Creating and populating an internal table that includes a component that is typed +"with a CDS simple type (sstring). Note: Built-in DDIC types such as sstring cannot +"directly be used in ABAP statements, except for typed literals. +TYPES: BEGIN OF s2, + comp1 TYPE i, + comp2 TYPE c LENGTH 3, + comp3 TYPE zdemo_abap_string, + END OF s2, + tab_type_2 TYPE TABLE OF s2 WITH EMPTY KEY. +DATA(itab2) = VALUE tab_type_2( ( comp1 = 1 comp2 = 'aaa' comp3 = `ABAP` ) ). + +"Unlike above, the following SELECT statements are possible +SELECT SINGLE * FROM @itab2 AS it WHERE comp1 = 1 INTO @DATA(res6). +SELECT SINGLE comp1 FROM @itab2 AS it WHERE comp3 = `ABAP` INTO @DATA(res7). +SELECT SINGLE comp1, comp3 FROM @itab2 AS it WHERE comp2 = 'aaa' AND comp3 = `ABAP` INTO @DATA(res8). +"Note: `ABAP` represents a literal of type string. When specifying it here +"like it is specified above, there is an implicit conversion. The following +"example uses a typed literal. +SELECT SINGLE comp1, comp2, comp3 FROM @itab2 AS it WHERE comp3 = sstring`ABAP` INTO @DATA(res9). +``` + +

⬆️ back to top

+ +#### Excursion: Joining/Merging Internal Tables into Internal Tables + +The following code snippets demonstrate joining/merging the content of two simple internal tables into another table. There may be several ways to achieve this. Here, the intention is to give an idea and, in particular, to emphasize SQL functionalities also available for internal tables (note the restrictions mentioned above and in the documentation). + +Assumptions: +- The target table is either created inline or exists and includes components from the source tables or components that can be mapped. +- One or more components are common between the source tables to perform a join or merge the table content. + +The code snippet shows a selection of syntax options and includes the following statements: +- Joins with `SELECT` (`INNER JOIN`, `LEFT OUTER JOIN`, CTE) +- Loops with `LOOP AT` statements, `FOR` loops using the `VALUE` and `REDUCE` operators + +```abap +"Creating two internal tables whose content will be joined. The shared +"value is represented by the key1 and key2 components. +"Sorted tables are used in the example (having key1/key2 as unique keys) +"to have unique values to perform joins. +TYPES: BEGIN OF s1, + key1 TYPE i, + a TYPE c LENGTH 1, + b TYPE c LENGTH 1, + c TYPE c LENGTH 1, + END OF s1, + tab_type1 TYPE SORTED TABLE OF s1 WITH UNIQUE KEY key1, + BEGIN OF s2, + key2 TYPE i, + d TYPE c LENGTH 1, + e TYPE c LENGTH 1, + END OF s2, + tab_type2 TYPE SORTED TABLE OF s2 WITH UNIQUE KEY key2. + +"Populating demo internal tables +DATA(itab1) = VALUE tab_type1( ( key1 = 1 a = 'a' b = 'b' c = 'c' ) + ( key1 = 2 a = 'd' b = 'e' c = 'f' ) + ( key1 = 3 a = 'g' b = 'h' c = 'i' ) ). + +DATA(itab2) = VALUE tab_type2( ( key2 = 1 d = 'j' e = 'k' ) + ( key2 = 2 d = 'l' e = 'm' ) ). + +"SELECT statement, inner join +"Note: With the inner join, the target table contains all +"combinations of rows for whose columns the join condition +"is true. +SELECT a~key1, a~a, a~b, b~d, b~e + FROM @itab1 AS a + INNER JOIN @itab2 AS b ON a~key1 = b~key2 + INTO TABLE @DATA(itab3). + +*Result +*KEY1 A B D E +*1 a b j k +*2 d e l m + +"SELECT statement, left outer join +"In contrast to the inner join above, the target table here +"also contains the table row of the first table for which +"no equivalent row exists in the second table. +SELECT a~key1, a~a, a~b, b~d, b~e + FROM @itab1 AS a + LEFT OUTER JOIN @itab2 AS b ON a~key1 = b~key2 + INTO TABLE @DATA(itab4). + +*Result +*KEY1 A B D E +*1 a b j k +*2 d e l m +*3 g h + +*&---------------------------------------------------------------------* +*& Note: The following statements produce the same result as the +*& previous example (itab4). +*&---------------------------------------------------------------------* + +"Common table expression +WITH +it1 AS ( SELECT a~key1, a~a, a~b FROM @itab1 AS a ), + +it2 AS ( SELECT b~key2, b~d, b~e FROM @itab2 AS b ) +SELECT +it1~key1, +it1~a, +it1~b, +it2~d, +it2~e FROM +it1 LEFT JOIN +it2 ON +it1~key1 = +it2~key2 +INTO TABLE @DATA(itab5). + +"LOOP statements +"Using the CORRESPONDING operator to assign identically named components, +"BASE retains existing content +"The assignment with CORRESPONDING ... BASE ... includes a table expression +"in which table lines are read and inserted based on the key mapping. With the +"OPTIONAL addition, errors can be avoided if a line does not exist. +DATA itab6 LIKE itab4. +LOOP AT itab1 INTO DATA(wa1). + INSERT CORRESPONDING #( wa1 ) INTO TABLE itab6 REFERENCE INTO DATA(ref). + ref->* = CORRESPONDING #( BASE ( ref->* ) VALUE #( itab2[ key2 = ref->key1 ] OPTIONAL ) ). +ENDLOOP. +"Assume the second table's shared component was also key1. In the second CORRESPONDING +"you could then work with the EXCEPT addition to not overwrite the identically named +"component. + +"Example similar to the previous one +"Also here, a table expression is used to read a line from +"the second internal table. The INSERT statement (without +"CORRESPONDING) includes the concrete value assignments +"with the VALUE operator. +DATA itab7 LIKE itab4. +LOOP AT itab1 INTO DATA(wa2). + DATA(line) = VALUE #( itab2[ key2 = wa2-key1 ] OPTIONAL ). + + INSERT VALUE #( key1 = wa2-key1 + a = wa2-a + b = wa2-b + d = line-d + e = line-e ) INTO TABLE itab7. +ENDLOOP. + +"Example using a FOR loop with the VALUE operator +TYPES tt_type3 LIKE itab4. +DATA(itab8) = VALUE tt_type3( FOR wa3 IN itab1 + ( key1 = wa3-key1 + a = wa3-a + b = wa3-b + d = VALUE #( itab2[ key2 = wa3-key1 ]-d OPTIONAL ) + e = VALUE #( itab2[ key2 = wa3-key1 ]-e OPTIONAL ) ) ). + +"Similar example that includes a LET expression +DATA(itab9) = VALUE tt_type3( FOR wa4 IN itab1 + LET tab_line = VALUE #( itab2[ key2 = wa4-key1 ] OPTIONAL ) IN + ( key1 = wa4-key1 + a = wa4-a + b = wa4-b + d = tab_line-d + e = tab_line-e ) ). + +"Example using a FOR loop with the REDUCE operator and LET +DATA(itab10) = REDUCE tt_type3( INIT tab = VALUE #( ) + FOR wa5 IN itab1 + LET tableline = VALUE #( itab2[ key2 = wa5-key1 ] OPTIONAL ) IN + NEXT tab = VALUE #( BASE tab + ( key1 = wa5-key1 + a = wa5-a + b = wa5-b + d = tableline-d + e = tableline-e ) ) ). +``` + +

⬆️ back to top

## Excursions diff --git a/02_Structures.md b/02_Structures.md index 63a50e4..f4e7f93 100644 --- a/02_Structures.md +++ b/02_Structures.md @@ -1225,9 +1225,9 @@ CLASS zcl_demo_abap IMPLEMENTATION. "Demonstrating prominent sy components that can be used in ABAP for Cloud Development - "------------------------------------------------------------------------------ - "------------------ sy-subrc: Return code of ABAP statements ------------------ - "------------------------------------------------------------------------------ +*&---------------------------------------------------------------------* +*& sy-subrc: Return code of ABAP statements +*&---------------------------------------------------------------------* "Many ABAP statements set a sy-subrc value. Check the ABAP Keyword Documentation "for individual statements. Usually, the value 0 indicates a successful execution. @@ -1287,9 +1287,9 @@ CLASS zcl_demo_abap IMPLEMENTATION. out->write( `DELETE: No match according to the WHERE condition.` ). ENDIF. - "------------------------------------------------------------------------------ - "--------------------------- sy-index: Loop indexes --------------------------- - "------------------------------------------------------------------------------ +*&---------------------------------------------------------------------* +*& sy-index: Loop indexes +*&---------------------------------------------------------------------* CLEAR some_string. @@ -1323,10 +1323,10 @@ CLASS zcl_demo_abap IMPLEMENTATION. ASSERT some_string = `123456789`. - "------------------------------------------------------------------------------ - "------------------- sy-tabix: Row index of internal tables ------------------- - "------------------------------------------------------------------------------ - +*&---------------------------------------------------------------------* +*& sy-tabix: Row index of internal tables +*&---------------------------------------------------------------------* + "Demo standard internal table with 5 entries DATA(std_itab) = VALUE string_table( ( `a` ) ( `b` ) ( `c` ) ( `d` ) ( `e` ) ). @@ -1388,9 +1388,9 @@ CLASS zcl_demo_abap IMPLEMENTATION. ENDLOOP. ASSERT some_string = `00000`. - "------------------------------------------------------------------------------ - "------------------------ sy-dbcnt: Edited table rows ------------------------- - "------------------------------------------------------------------------------ +*&---------------------------------------------------------------------* +*& sy-dbcnt: Edited table rows +*&---------------------------------------------------------------------* DELETE FROM zdemo_abap_tab1. DATA(dbcnt) = sy-dbcnt. @@ -1412,9 +1412,10 @@ CLASS zcl_demo_abap IMPLEMENTATION. DELETE FROM zdemo_abap_tab1 WHERE num1 IS INITIAL. ASSERT sy-dbcnt = 3. - "------------------------------------------------------------------------------ - "------------- sy-fdpos: Occurrence in byte or character strings -------------- - "------------------------------------------------------------------------------ +*&---------------------------------------------------------------------* +*& sy-fdpos: Occurrence in byte or character strings +*&---------------------------------------------------------------------* + "For example, relevant in comparison expressions such as CS (constains string). "If the comparison is true, sy-fdpos contains the offset of the found value. If it "is false, sy-fdpos contains the length of the searched string. @@ -1556,10 +1557,10 @@ CLASS zcl_demo_abap IMPLEMENTATION. "---- Comment in/out END ---- DO 100000 TIMES. - "------------------------------------------------------------------------ - "----------------------------- Comparison 1 ----------------------------- - "------------------------------------------------------------------------ - +*&---------------------------------------------------------------------* +*& Comparison 1 +*&---------------------------------------------------------------------* + "1) Internal table with boxed components: All boxed components empty "---- Comment in/out START ---- @@ -1578,9 +1579,9 @@ CLASS zcl_demo_abap IMPLEMENTATION. ************************************************************************************************** - "------------------------------------------------------------------------ - "----------------------------- Comparison 2 ----------------------------- - "------------------------------------------------------------------------ +*&---------------------------------------------------------------------* +*& Comparison 2 +*&---------------------------------------------------------------------* "3) Internal table with boxed components: All boxed components filled @@ -1604,9 +1605,9 @@ CLASS zcl_demo_abap IMPLEMENTATION. ************************************************************************************************** - "------------------------------------------------------------------------ - "----------------------------- Comparison 3 ----------------------------- - "------------------------------------------------------------------------ +*&---------------------------------------------------------------------* +*& Comparison 3 +*&---------------------------------------------------------------------* "5) Internal table with boxed components: Only few boxed components filled diff --git a/03_ABAP_SQL.md b/03_ABAP_SQL.md index 264edd8..8a0f99a 100644 --- a/03_ABAP_SQL.md +++ b/03_ABAP_SQL.md @@ -2389,7 +2389,10 @@ UPDATE dbtab FROM TABLE @itab. UPDATE dbtab FROM TABLE @( VALUE #( ( comp1 = ... comp2 = ... ) ( comp1 = ... comp2 = ... ) ) ). -"-------------------------- SET addition -------------------------- +*&---------------------------------------------------------------------* +*& SET addition +*&---------------------------------------------------------------------* + "Changing values of specific fields without overwriting other, non-specified "fields "Changing values of specific fields in all table rows @@ -2409,7 +2412,10 @@ UPDATE dbtab SET comp2 = 'X', comp3 = 'Y' WHERE comp4 > 100. "in the WHERE clause UPDATE dbtab SET comp2 = 'X' WHERE key_field = 'Y'. -"--------------- INDICATORS ... SET STRUCTURE addition --------------- +*&---------------------------------------------------------------------* +*& INDICATORS ... SET STRUCTURE addition +*&---------------------------------------------------------------------* + "Similar to SET, using the INDICATORS ... addition, you can change content "of specific fields without overwriting existing values of other fields by "specifying set indicators. @@ -2501,7 +2507,10 @@ For more information about constructor expressions, see the ABAP Keyword Documen The following examples show a selection. The previous code snippets already include the use of the `VALUE` operator with which structures and internal tables can be created in place. ```abap -"--- VALUE --- +*&---------------------------------------------------------------------* +*& VALUE +*&---------------------------------------------------------------------* + "VALUE operator as shown above, creating an internal table in place INSERT dbtab FROM TABLE @( VALUE #( ( key_field = 1 comp1 = ... ) ( key_field = 2 comp1 = ... ) @@ -2533,7 +2542,10 @@ SELECT SINGLE * FROM dbtab WHERE key_field = ... INTO @DATA(read_line). "original content and are not initialized when writing to the database table. UPDATE dbtab FROM @( VALUE #( BASE read_line comp2 = ... comp4 = ... ) ). -"--- CORRESPONDING --- +*&---------------------------------------------------------------------* +*& CORRESPONDING +*&---------------------------------------------------------------------* + "The following example assumes that some_itab has a different line type than dbtab. "I.e. some_itab may have more components that are not available in dbtab. The "corresponding fields with identical names are used. It is assumed that the components' @@ -2572,8 +2584,10 @@ CLASS zcl_demo_abap IMPLEMENTATION. METHOD if_oo_adt_classrun~main. - "--------------------------- INSERT --------------------------- - +*&---------------------------------------------------------------------* +*& INSERT +*&---------------------------------------------------------------------* + "Deleting the contents of a demo database table to start with an empty database table DELETE FROM zdemo_abap_tab1. @@ -2645,9 +2659,9 @@ CLASS zcl_demo_abap IMPLEMENTATION. SELECT * FROM zdemo_abap_tab1 INTO TABLE @DATA(itab_insert). out->write( data = itab_insert name = `itab_insert` ). -********************************************************************** - - "--------------------------- UPDATE --------------------------- +*&---------------------------------------------------------------------* +*& UPDATE +*&---------------------------------------------------------------------* "Preparing a demo database table DELETE FROM zdemo_abap_tab1. @@ -2721,9 +2735,10 @@ CLASS zcl_demo_abap IMPLEMENTATION. SELECT * FROM zdemo_abap_tab1 INTO TABLE @DATA(itab_update_set). out->write( data = itab_update_set name = `itab_update_set` ). -********************************************************************** +*&---------------------------------------------------------------------* +*& MODIFY +*&---------------------------------------------------------------------* - "--------------------------- MODIFY --------------------------- "The examples include INSERT statements to prepare the database table. "Deleting the contents of a demo database table to start with an empty database table @@ -2753,9 +2768,9 @@ CLASS zcl_demo_abap IMPLEMENTATION. SELECT * FROM zdemo_abap_tab1 INTO TABLE @DATA(itab_modify). out->write( data = itab_modify name = `itab_modify` ). -********************************************************************** - - "--------------------------- DELETE --------------------------- +*&---------------------------------------------------------------------* +*& DELETE +*&---------------------------------------------------------------------* "Deleting the contents of a demo database table to start with an empty database table DELETE FROM zdemo_abap_tab1. @@ -2790,9 +2805,10 @@ CLASS zcl_demo_abap IMPLEMENTATION. SELECT * FROM zdemo_abap_tab1 INTO TABLE @itab_delete. out->write( data = itab_delete name = `itab_delete` ). -********************************************************************** +*&-----------------------------------------------------------------------* +*& Exploring constructor expressions for internal tables created in place +*&-----------------------------------------------------------------------* - "-------- Exploring constructor expressions for internal tables created in place -------- "For more information about constructor expressions, see the ABAP Keyword Documentation and the "Constructor Expressions cheat sheet. Many additions are available. The examples show a "selection. @@ -2886,7 +2902,7 @@ SELECT * - CDS artifacts are available that allow not only reading but also creating, updating, and deleting. - **Table Entities** - Table entities are CDS entities that define database tables on the SAP HANA database linked to AS ABAP. - - They are - with restructions currently - considered successors of the classic DDIC database table, and also represent global structured types usable in ABAP. + - They are - with restrictions currently - considered successors of the classic DDIC database table, and also represent global structured types usable in ABAP. - Syntax: `define table entity ...`. - For more information, refer to the ABAP Data Models guide, for example, [here](https://help.sap.com/docs/ABAP_Cloud/aaae421481034feab3e71dd9e0f643bf/100ab51935544f18b4f4be9b4abb91e8.html). - **Writable CDS View Entities** @@ -3164,7 +3180,10 @@ The following example explores the setting of `sy-subrc` and `sy-dbcnt` by ABAP "Clearing a demo database table DELETE FROM zdemo_abap_tab1. -"--------------------- INSERT --------------------- +*&---------------------------------------------------------------------* +*& INSERT +*&---------------------------------------------------------------------* + INSERT zdemo_abap_tab1 FROM @( VALUE #( key_field = 1 ) ). ASSERT sy-subrc = 0. @@ -3188,7 +3207,10 @@ INSERT zdemo_abap_tab1 FROM TABLE @( VALUE #( ( key_field = 3 ) ASSERT sy-subrc = 4. ASSERT sy-dbcnt = 1. -"--------------------- UPDATE --------------------- +*&---------------------------------------------------------------------* +*& UPDATE +*&---------------------------------------------------------------------* + UPDATE zdemo_abap_tab1 FROM @( VALUE #( key_field = 1 num1 = 1 ) ). ASSERT sy-subrc = 0. @@ -3211,7 +3233,10 @@ UPDATE zdemo_abap_tab1 FROM TABLE @( VALUE #( ( key_field = 4 num1 = 4 ) ASSERT sy-subrc = 4. ASSERT sy-dbcnt = 1. -"--------------------- MODIFY --------------------- +*&---------------------------------------------------------------------* +*& MODIFY +*&---------------------------------------------------------------------* + MODIFY zdemo_abap_tab1 FROM @( VALUE #( key_field = 1 num1 = 11 ) ). ASSERT sy-subrc = 0. @@ -3223,7 +3248,9 @@ MODIFY zdemo_abap_tab1 FROM TABLE @( VALUE #( ( key_field = 2 num1 = 22 ) "E ASSERT sy-subrc = 0. ASSERT sy-dbcnt = 2. -"--------------------- SELECT --------------------- +*&---------------------------------------------------------------------* +*& SELECT +*&---------------------------------------------------------------------* SELECT * FROM zdemo_abap_tab1 @@ -3249,7 +3276,10 @@ SELECT * ASSERT sy-subrc = 4. ASSERT sy-dbcnt = 0. -"--------------------- DELETE --------------------- +*&---------------------------------------------------------------------* +*& DELETE +*&---------------------------------------------------------------------* + DELETE zdemo_abap_tab1 FROM @( VALUE #( key_field = 1 ) ). ASSERT sy-subrc = 0. ASSERT sy-dbcnt = 1. diff --git a/04_ABAP_Object_Orientation.md b/04_ABAP_Object_Orientation.md index 030faed..afdbdf8 100644 --- a/04_ABAP_Object_Orientation.md +++ b/04_ABAP_Object_Orientation.md @@ -414,7 +414,7 @@ CLASS zcl_demo_abap IMPLEMENTATION. METHOD if_oo_adt_classrun~main. - "---- The method called has formal parameters using type declarations from the CCDEF include ---- + "The method called has formal parameters using type declarations from the CCDEF include TRY. DATA(result1) = calculate( num1 = 10 operator = '+' num2 = 4 ). out->write( data = result1 name = `result1` ). @@ -436,13 +436,13 @@ CLASS zcl_demo_abap IMPLEMENTATION. out->write( `Operator not allowed` ). ENDTRY. - "---- Using local class implemented in the CCIMP include ---- + "Using local class implemented in the CCIMP include DATA(hi1) = lcl_demo=>say_hello( ). out->write( data = hi1 name = `hi1` ). DATA(hi2) = lcl_demo=>say_hello( xco_cp=>sy->user( )->name ). out->write( data = hi2 name = `hi2` ). - "--------------- Test include (CCAU) --------------- + "Test include (CCAU) "For running the ABAP Unit test, choose CTRL+Shift+F10 in ADT. "Or you can make a right click in the class code, choose "'Run As' and '4 ABAP Unit Test'. @@ -896,49 +896,49 @@ CLASS zcl_demo_abap DEFINITION "Note: The example parameters are all specified for passing "actual parameters by reference. METHODS: meth IMPORTING - "---- Non-generic built-in ABAP types ---- + "Non-generic built-in ABAP types i_a TYPE i i_b TYPE string - "---- ABAP DDIC types ---- + "ABAP DDIC types i_c TYPE land1 "elementary type i_d TYPE timestampl "elementary type i_e TYPE zdemo_abap_fli "structured type based on DDIC database table i_f TYPE string_hashed_table "table type - "---- ABAP CDS types (all of the examples are structured types) ---- + "ABAP CDS types (all of the examples are structured types) i_g TYPE zdemo_abap_fli_ve "CDS view entity i_h TYPE zdemo_abap_abstract_ent "CDS abstract entity i_i TYPE zdemo_abap_table_function "CDS table function - "---- Data types declared in public section of a class ---- + "Data types declared in public section of a class i_j TYPE zcl_demo_abap_dtype_dobj=>t_pub_text_c30 "elementary type i_k TYPE zcl_demo_abap_amdp=>carr_fli_struc "structured type i_l TYPE zcl_demo_abap_amdp=>carr_fli_tab "table type - "---- Data types declared in an interface ---- + "Data types declared in an interface i_m TYPE zdemo_abap_get_data_itf=>occ_rate "elementary type i_n TYPE zdemo_abap_get_data_itf=>carr_tab "table type - "---- Local types ---- + "Local types i_o TYPE c3 "elementary type i_p TYPE der_type "table type (BDEF derived type) - "---- Note: Examples such as the following are not allowed type specifications of formal parameters. ---- - "---- In the following cases, extra (local) type declarations with TYPES are required before the -------- - "---- method declaration to type the formal parameters. ------------------------------------------------- + "Note: Examples such as the following are not allowed type specifications of formal parameters. + "In the following cases, extra (local) type declarations with TYPES are required before the + "method declaration to type the formal parameters. "i_no1 TYPE c LENGTH 3 "i_no2 TYPE TABLE OF zdemo_abap_fli WITH EMPTY KEY - "---- Reference types ---- + "Reference types i_q TYPE REF TO i "Data reference i_r TYPE REF TO zdemo_abap_carr "Data reference i_s TYPE REF TO zcl_demo_abap_unit_test "Object reference i_t TYPE REF TO data "Data reference (considered as complete typing, too) i_u TYPE REF TO object "Object reference (considered as complete typing, too) - "---- TYPE LINE OF addition (structured type based on a table type) ---- + "TYPE LINE OF addition (structured type based on a table type) i_v TYPE LINE OF zcl_demo_abap_amdp=>carr_fli_tab i_w TYPE LINE OF der_type - "---- LIKE addition (types based on existing data objects) ---- + "LIKE addition (types based on existing data objects) i_x LIKE int "Local data object i_y LIKE zcl_demo_abap_dtype_dobj=>comma "Constant specified in a class i_z LIKE zdemo_abap_objects_interface=>stat_str "Data object specified in an interface - "---- LIKE LINE OF addition (types based on existing internal tables) ---- + "LIKE LINE OF addition (types based on existing internal tables) i_1 LIKE LINE OF itab "Local internal table - "---- LIKE REF TO addition (reference types based on existing data object) ---- + "LIKE REF TO addition (reference types based on existing data object) i_2 LIKE REF TO int "Local elementary data object i_3 LIKE REF TO itab "Local internal table . @@ -985,11 +985,11 @@ CLASS zcl_demo_abap DEFINITION "Example method demonstrating the generic typing of formal parameters METHODS: meth IMPORTING - "---- Any data type ---- + "Any data type i_data TYPE data i_any TYPE any - "---- Character-like types ---- + "Character-like types i_c TYPE c "Text field with a generic length i_clike TYPE clike "Character-like (c, n, string, d, t, and character-like flat structures) i_csequence TYPE csequence "Text-like (c, string) @@ -997,12 +997,12 @@ CLASS zcl_demo_abap DEFINITION i_x TYPE x "Byte field with generic length i_xsequence TYPE xsequence "Byte-like (x, xstring) - "---- Numeric types ---- + "Numeric types i_decfloat TYPE decfloat "decfloat16 decfloat34 i_numeric TYPE numeric "Numeric (i, int8, p, decfloat16, decfloat34, f, (b, s)) i_p TYPE p "Packed number (generic length and number of decimal places) - "---- Internal table types ---- + "Internal table types i_any_table TYPE ANY TABLE "Internal table with any table type i_hashed_table TYPE HASHED TABLE i_index_table TYPE INDEX TABLE @@ -1010,7 +1010,7 @@ CLASS zcl_demo_abap DEFINITION i_standard_table TYPE STANDARD TABLE i_table TYPE table "Standard table - "---- Other types ---- + "Other types i_simple TYPE simple "Elementary data type including enumerated types and "structured types with exclusively character-like flat components . @@ -2189,9 +2189,9 @@ ENDCLASS. CLASS zcl_demo_abap IMPLEMENTATION. METHOD if_oo_adt_classrun~main. - "---------------------------------------------------------------- - "-------- Method chaining with a functional method call --------- - "---------------------------------------------------------------- +*&---------------------------------------------------------------------* +*& Method chaining with a functional method call +*&---------------------------------------------------------------------* "Hallo NAME. This is an example of method chaining. DATA(text1) = NEW zcl_demo_abap( @@ -2250,9 +2250,9 @@ CLASS zcl_demo_abap IMPLEMENTATION. out->write( text2 ). - "---------------------------------------------------------------- - "-------- Method chaining with a standalone statement ----------- - "---------------------------------------------------------------- +*&---------------------------------------------------------------------* +*& Method chaining with a standalone statement +*&---------------------------------------------------------------------* "In the example, the final method call in the chain receives "the classrun instance available in the implementation of the @@ -2321,7 +2321,10 @@ CLASS zcl_demo_abap DEFINITION PUBLIC SECTION. INTERFACES if_oo_adt_classrun. - "------------------------ Attributes ------------------------ +*&---------------------------------------------------------------------* +*& Attributes +*&---------------------------------------------------------------------* + "Instance attributes DATA: inst_attr TYPE utclong, inst_string TYPE string. @@ -2335,7 +2338,10 @@ CLASS zcl_demo_abap DEFINITION "subclasses (note that the example class does not allow inheritance). CLASS-DATA read_only_attr TYPE string VALUE `read only` READ-ONLY. - "------------------------ Methods ------------------------ +*&---------------------------------------------------------------------* +*& Methods +*&---------------------------------------------------------------------* + "The parameter interfaces (signatures) of the methods are intended to "demonstrate various syntax options described in the cheat sheet. @@ -2424,7 +2430,9 @@ CLASS zcl_demo_abap IMPLEMENTATION. "To demonstrate 'calls from external', an instance of the class is "nevertheless created in the example. - "--------------- Constructors --------------- +*&---------------------------------------------------------------------* +*& Constructors +*&---------------------------------------------------------------------* "Instance constructor: Automatically called when a class is instantiated "and an instance is created. @@ -2494,7 +2502,9 @@ CLASS zcl_demo_abap IMPLEMENTATION. DATA(d) = zcl_demo_abap=>stat_attr. DATA(e) = oref->stat_attr. - "--------------- Method calls --------------- +*&---------------------------------------------------------------------* +*& Method calls +*&---------------------------------------------------------------------* "Calling instance methods "Instance methods are called using the object component selector -> @@ -5920,7 +5930,9 @@ CL_ABAP_TYPEDESCR Examples: ```abap -"------------ Object reference variables ------------ +*&---------------------------------------------------------------------* +*& Object reference variables +*&---------------------------------------------------------------------* "Static and dynamic types "Defining an object reference variable with a static type @@ -5941,7 +5953,9 @@ DATA tdo_elem TYPE REF TO cl_abap_elemdescr. DATA tdo_data TYPE REF TO cl_abap_datadescr. DATA tdo_gen_obj TYPE REF TO object. -"------------ Upcasts ------------ +*&---------------------------------------------------------------------* +*& Upcasts +*&---------------------------------------------------------------------* "Moving up the inheritance tree "Assignments: @@ -5980,7 +5994,9 @@ DATA(tdo_inl_cast) = CAST cl_abap_typedescr( tdo_elem ). CLEAR: tdo_super, tdo_elem, tdo_data, tdo_gen_obj. -"------------ Downcasts ------------ +*&---------------------------------------------------------------------* +*& Downcasts +*&---------------------------------------------------------------------* "Moving down the inheritance tree "Assignments: @@ -6056,7 +6072,10 @@ ENDTRY. "- non-initial object reference variables, the dynamic type is checked. "- initial object reference variables, the static type is checked. -"------------ IS INSTANCE OF ------------ +*&---------------------------------------------------------------------* +*& IS INSTANCE OF +*&---------------------------------------------------------------------* + DATA some_type_descr_obj TYPE REF TO cl_abap_typedescr. some_type_descr_obj = cl_abap_typedescr=>describe_by_data( str_table ). @@ -6098,7 +6117,10 @@ ELSE. ... ENDIF. -"------------ CASE TYPE OF ------------ +*&---------------------------------------------------------------------* +*& CASE TYPE OF +*&---------------------------------------------------------------------* + "The examples are desinged similarly to the IS INSTANCE OF examples. DATA(dref) = REF #( str_table ). diff --git a/05_Constructor_Expressions.md b/05_Constructor_Expressions.md index 8c0db84..82c4a97 100644 --- a/05_Constructor_Expressions.md +++ b/05_Constructor_Expressions.md @@ -672,8 +672,8 @@ DATA(it_val_1) = VALUE string_table( FOR GROUPS gr OF wa IN itab4grp The following table includes a selection of various possible additions to this operator. There are more variants available (also [RAP](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenrap_glosry.htm "Glossary Entry")-specific ones) -that are not covered. Find more information in [this -topic](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenconstructor_expr_corresponding.htm) of the ABAP Keyword Documentation. +that are not covered here. Find more information in [this +topic](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenconstructor_expr_corresponding.htm) of the ABAP Keyword Documentation, and example snippets in the executable example. | Addition | Details | @@ -690,7 +690,9 @@ topic](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file Examples: ``` abap -"-------------- Patterns ------------- +*&---------------------------------------------------------------------* +*& Patterns +*&---------------------------------------------------------------------* "The following examples demonstrate simple assignments "with the CORRESPONDING operator using these syntax patterns. @@ -705,7 +707,9 @@ Examples: "... CORRESPONDING #( z EXCEPT b ) ... "... CORRESPONDING #( it DISCARDING DUPLICATES ) ... -"-------------- Structures ------------- +*&---------------------------------------------------------------------* +*& Structures +*&---------------------------------------------------------------------* "Data objects to work with in the examples "Two different structures; one component differs. @@ -767,7 +771,9 @@ s2 = CORRESPONDING #( s1 MAPPING d = c EXCEPT * ). *A B D *0 bbbbb -"-------------- Internal tables ------------- +*&---------------------------------------------------------------------* +*& Internal tables +*&---------------------------------------------------------------------* "Internal tables to work with in the examples DATA it1 LIKE TABLE OF s1 WITH EMPTY KEY. @@ -817,7 +823,10 @@ it2 = CORRESPONDING #( it1 DISCARDING DUPLICATES ). *4 aaa *5 eee -"-------------- DEFAULT addition when using MAPPING ------------- +*&---------------------------------------------------------------------* +*& DEFAULT addition when using MAPPING +*&---------------------------------------------------------------------* + "- This addition allows the assignment of values for a target component based " on an expression (which is evaluated before the CORRESPONDING expression). "- DEFAULT can be preceded by the source component. In this case, the source @@ -849,7 +858,10 @@ DATA itab1 LIKE TABLE OF struc1 WITH EMPTY KEY. "Populating structure struc1 = VALUE #( id1 = 1 a = `a` b = `b` c = 2 d = `d` e = 3 ). -"--------- Assignment using CORRESPONDING (DEFAULT only) --------- +*&---------------------------------------------------------------------* +*& Assignment using CORRESPONDING (DEFAULT only) +*&---------------------------------------------------------------------* + "- Component a: It is not specified but it is mapped anyway " due to the identical name and not being explicitly specified " for mapping @@ -873,8 +885,11 @@ struc2 = CORRESPONDING #( *ID2 A B C D Z *1 a hallo 6 hi 28 -"--- Assignment using CORRESPONDING (DEFAULT preceded by the source --- -"--- component on the right-hand side) -------------------------------- +*&---------------------------------------------------------------------* +*& Assignment using CORRESPONDING (DEFAULT preceded by the source +*& component on the right-hand side) +*&---------------------------------------------------------------------* + "- The example is similar to above. Various expressions are included " in combination with the DEFAULT addition "- Component a: It is not specified; see above. @@ -1166,6 +1181,7 @@ it6 = CORRESPONDING #( it5 FROM lookup_table USING KEY sk c = a d = b ) ##operat No parameters are passed for a class without an explicit instance constructor. See more information: [here](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abennew_constructor_params_class.htm). +- The `NEW` operator is also covered as part of the [ABAP Object Orientation](04_ABAP_Object_Orientation.md) cheat sheet. The following examples cover: - Creating anonymous data objects @@ -1173,7 +1189,10 @@ The following examples cover: ``` abap -"-------------- Creating anonymous data objects ------------- +*&---------------------------------------------------------------------* +*& Creating anonymous data objects +*&---------------------------------------------------------------------* + "Note that optional additions (see for VALUE expressions) when dealing "with anonymous data objects (e.g. BASE). They are not covered here. @@ -1210,7 +1229,9 @@ DATA dref5 TYPE REF TO string_table. dref5 = NEW string_table( ( `c` ) ( `d` ) ). DATA(dref6) = NEW string_table( VALUE #( ( `a` ) ( `b` ) ) ). -"-------------- Creating objects/instances of classes ------------- +*&---------------------------------------------------------------------* +*& Creating objects/instances of classes +*&---------------------------------------------------------------------* "Using a cheat sheet example class (the class does not implement constructors) DATA oref1 TYPE REF TO zcl_demo_abap_objects. @@ -1809,7 +1830,10 @@ fi_tab2 = fi_tab1. fi_tab3 = fi_tab1. fi_tab4 = fi_tab1. -"---------------- Basic form: Filtering using single values ---------------- +*&---------------------------------------------------------------------* +*& Basic form: Filtering using single values +*&---------------------------------------------------------------------* + "Syntax options for using a WHERE condition and the table key "Using the primary table key without specifying USING KEY @@ -1887,7 +1911,9 @@ DATA(f10) = FILTER #( fi_tab4 EXCEPT USING KEY sec_hash_key WHERE a = 3 AND b = *4 ddd klm *5 eee nop -"---------------- Basic form: Filtering using a filter table ---------------- +*&---------------------------------------------------------------------* +*& Basic form: Filtering using a filter table +*&---------------------------------------------------------------------* "In the WHERE condition, the columns of source and filter table are compared. "Those lines in the source table are used for which at least one line in the @@ -2098,7 +2124,9 @@ DATA(itab) = VALUE itab_type( ( col1 = 'a' col2 = 1 col3 = 30 ) ( col1 = 'bb' col2 = 2 col3 = 10 ) ( col1 = 'ccc' col2 = 3 col3 = 20 ) ). -"-------------- Table iterations -------------- +*&---------------------------------------------------------------------* +*& Table iterations +*&---------------------------------------------------------------------* DATA(it1) = VALUE itab_type( FOR wa IN itab ( col1 = wa-col1 && 'z' col2 = wa-col2 + 1 ) ). @@ -2144,7 +2172,9 @@ DATA(it3) = VALUE string_table( FOR IN itab INDEX INTO idx *Table index 2 -> COL1: "bb" / COL2: "2" / COL3: "10" *Table index 3 -> COL1: "ccc" / COL2: "3" / COL3: "20" -"---------- Excursions ---------- +*&---------------------------------------------------------------------* +*& Excursions +*&---------------------------------------------------------------------* "FOR expression are very handy, for example, in EML and other statements. "The following example commented out shows an EML statement in the implementation @@ -2293,7 +2323,10 @@ DATA(it11) = VALUE itab_type( FOR wa IN itab USING KEY primary_key ( col1 = wa-c *bbt 9 12 *ccct 9 13 -"---------- Conditional iterations ---------- +*&---------------------------------------------------------------------* +*& Conditional iterations +*&---------------------------------------------------------------------* + "Notes: "- When used with VALUE/NEW for internal tables: New table lines are created in " iteration steps and added to result @@ -2386,7 +2419,9 @@ DATA(itab) = VALUE itab_type( ( col1 = 'a' col2 = 1 col3 = 30 ) ( col1 = 'bb' col2 = 2 col3 = 10 ) ( col1 = 'ccc' col2 = 3 col3 = 20 ) ). -"---------- Table iterations ---------- +*&---------------------------------------------------------------------* +*& Table iterations +*&---------------------------------------------------------------------* "Calculating the sum of values in a table column "Result: 6 @@ -2443,7 +2478,9 @@ DATA(itred) = REDUCE s3_tab_type( INIT tab = VALUE s3_tab_type( ) *1 30 31 *2 10 12 -"---------- Conditional iterations ---------- +*&---------------------------------------------------------------------* +*& Conditional iterations +*&---------------------------------------------------------------------* "UNTIL addition "Iteratively calculating the sum from 1 to 10 diff --git a/06_Dynamic_Programming.md b/06_Dynamic_Programming.md index 2d47cbe..39f4aaa 100644 --- a/06_Dynamic_Programming.md +++ b/06_Dynamic_Programming.md @@ -80,7 +80,7 @@ - The ABAP compiler cannot check the dynamic programming feature like the `SELECT` statement mentioned above. There is no syntax warning or suchlike. - The checks are performed only at runtime, which has an impact on the performance. - The testing of [procedures](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenprocedure_glosry.htm "Glossary Entry") that include dynamic programming features may be difficult. - - Including external input in dynamic ABAP SQL statements without an appropriate handling, there can be potential security risks. You can, for example, use the `CL_ABAP_DYN_PRG` class to manage security risks. + - ⚠️ Dynamic programming techniques can pose significant security risks if not used correctly. You should thoroughly check or escape any dynamic content received from external sources before using it in dynamic statements. You can achieve this using the system class `CL_ABAP_DYN_PRG` or the built-in `escape` function.

⬆️ back to top

@@ -668,7 +668,9 @@ Excursion: Static vs. dynamic type, upcasts and downcasts The code snippet below demonstrates upcasts and downcasts with data reference variables, but also object reference variables to visualize moving up and down an inheritance tree. The examples in the code snippet use object reference variables to illustrate the class hierarchy of the [Runtime Type Services (RTTS)](#runtime-type-services-rtts), which is covered in more detail further down. You can find the hierarchy tree of the classes [here](#runtime-type-services-rtts). ``` abap -"------------ Object reference variables ------------ +*&---------------------------------------------------------------------* +*& Object reference variables +*&---------------------------------------------------------------------* "Static and dynamic types "Defining an object reference variable with a static type @@ -689,7 +691,9 @@ DATA tdo_elem TYPE REF TO cl_abap_elemdescr. DATA tdo_data TYPE REF TO cl_abap_datadescr. DATA tdo_gen_obj TYPE REF TO object. -"------------ Upcasts ------------ +*&---------------------------------------------------------------------* +*& Upcasts +*&---------------------------------------------------------------------* "Moving up the inheritance tree "Assignments: @@ -728,7 +732,9 @@ DATA(tdo_inl_cast) = CAST cl_abap_typedescr( tdo_elem ). CLEAR: tdo_super, tdo_elem, tdo_data, tdo_gen_obj. -"------------ Downcasts ------------ +*&---------------------------------------------------------------------* +*& Downcasts +*&---------------------------------------------------------------------* "Moving down the inheritance tree "Assignments: @@ -750,7 +756,9 @@ tdo_elem = CAST #( tdo_data ). "cl_abap_typedescr -> cl_abap_elemdescr tdo_elem = CAST #( tdo_super ). -"------------ Error prevention in downcasts ------------ +*&---------------------------------------------------------------------* +*& Error prevention in downcasts +*&---------------------------------------------------------------------* "In the examples above, the assignments work. The following code snippets "deal with examples in which a downcast is not possible. An exception is @@ -791,7 +799,10 @@ ENDTRY. "- non-initial object reference variables, the dynamic type is checked. "- initial object reference variables, the static type is checked. -"------------ IS INSTANCE OF ------------ +*&---------------------------------------------------------------------* +*& IS INSTANCE OF +*&---------------------------------------------------------------------* + DATA some_tdo TYPE REF TO cl_abap_typedescr. some_tdo = cl_abap_typedescr=>describe_by_data( str_table ). @@ -833,7 +844,10 @@ ELSE. ... ENDIF. -"------------ CASE TYPE OF ------------ +*&---------------------------------------------------------------------* +*& CASE TYPE OF +*&---------------------------------------------------------------------* + "The examples are desinged similarly to the IS INSTANCE OF examples. DATA(dref) = REF #( str_table ). @@ -871,9 +885,9 @@ CASE TYPE OF initial_tdo. ... ENDCASE. -********************************************************************** - -"------------ Data reference variables ------------ +*&---------------------------------------------------------------------* +*& Data reference variables +*&---------------------------------------------------------------------* "Declaring data reference variables DATA ref1 TYPE REF TO i. @@ -1196,7 +1210,10 @@ DATA dobj TYPE string VALUE `hallo`. "The following examples use a field symbol with generic type FIELD-SYMBOLS TYPE data. -"------- Specifying the memory area dynamically ------ +*&---------------------------------------------------------------------* +*& Specifying the memory area dynamically +*&---------------------------------------------------------------------* + "I.e. the memory area is not specified directly, but as content of a "character-like data object in parentheses. "Note: @@ -1240,7 +1257,10 @@ DATA(some_named_dobj) = 'SOME_STRING'. "Development. "ASSIGN (some_named_dobj) TO FIELD-SYMBOL(). -"------- Assigning components dynamically ------ +*&---------------------------------------------------------------------* +*& Assigning components dynamically +*&---------------------------------------------------------------------* + "You can chain the names with the component selector (-), or, in "case of reference variables, the object component selector (->). ASSIGN st-('COL1') TO . @@ -1271,7 +1291,10 @@ ASSIGN st-(0) TO . ASSIGN COMPONENT 'COL1' OF STRUCTURE st TO . ASSIGN COMPONENT 3 OF STRUCTURE st TO . -"------- Assigning attributes of classes or interfaces dynamically ------ +*&---------------------------------------------------------------------* +*& Assigning attributes of classes or interfaces dynamically +*&---------------------------------------------------------------------* + "The following syntax pattern shows the possible specifications. "... cref->(attr_name) ... "object reference variable "... iref->(attr_name) ... "interface reference variable @@ -1327,7 +1350,10 @@ ASSERT sy-subrc = 0 AND IS ASSIGNED. ASSIGN ('DOES_NOT_EXIST') TO ELSE UNASSIGN. ASSERT sy-subrc = 4 AND IS NOT ASSIGNED. -"------- Assigments and casting a dynamically specified type ------ +*&---------------------------------------------------------------------* +*& Assigments and casting a dynamically specified type +*&---------------------------------------------------------------------* + "Pattern: ASSIGN ... TO CASTING TYPE (type_name). "Assigning a data object to a field symbol casting a dynamically @@ -1369,7 +1395,9 @@ ENDLOOP. *Error! Exception raised: CX_SY_ASSIGN_CAST_UNKNOWN_TYPE; 'ASSIGN ... CASTING failed; NOPE is an unknown type' *Error! Exception raised: CX_SY_ASSIGN_CAST_ILLEGAL_CAST; 'ASSIGN ... CASTING failed: Incompatible type' -"------- Assigments and dynamic casting using a type description object ------ +*&---------------------------------------------------------------------* +*& Assigments and dynamic casting using a type description object +*&---------------------------------------------------------------------* "Note: As covered further down and in the executable example, "CREATE DATA and ASSIGN statements have the HANDLE addition @@ -1395,7 +1423,10 @@ ASSIGN dobj_c10 TO CASTING TYPE HANDLE tdo_elem. "1234 - You can also use type description objects and the [`TYPE HANDLE` addition](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abapcreate_data_handle.htm) to create anonymous data objects dynamically. For this and the absolute names, find more information below in the section about RTTS. ``` abap -"------------ CREATE DATA statement patterns ---------------- +*&---------------------------------------------------------------------* +*& CREATE DATA statement patterns +*&---------------------------------------------------------------------* + "CREATE DATA dref TYPE (typename) ... "CREATE DATA dref TYPE ... TABLE OF (typename) ... "CREATE DATA dref TYPE REF TO (typename). @@ -1404,7 +1435,9 @@ ASSIGN dobj_c10 TO CASTING TYPE HANDLE tdo_elem. "1234 "CREATE DATA dref TYPE (absolute_name). "CREATE DATA dref TYPE HANDLE type_description_object. -"------------ Specifying a type name dynamically ------------ +*&---------------------------------------------------------------------* +*& Specifying a type name dynamically +*&---------------------------------------------------------------------* "Anonymous data objects are created using a type determined at "runtime. In this case, the name of the data type is specified @@ -1432,8 +1465,9 @@ DATA carr_tab TYPE TABLE OF zdemo_abap_carr WITH EMPTY KEY. TYPES t_str_ref TYPE REF TO string. DATA str_ref TYPE REF TO string. - -"----- Pattern: TYPE (typename) ... ----- +*&---------------------------------------------------------------------* +*& Pattern: TYPE (typename) ... +*&---------------------------------------------------------------------* "Creating an elementary data object "Specifying a literal for the dynamic type name (used in most of the @@ -1453,7 +1487,9 @@ CREATE DATA dref TYPE ('T_CARR_TAB'). "Data reference CREATE DATA dref TYPE ('T_STR_REF'). -"----- Pattern: TYPE ... TABLE OF (typename) ... ----- +*&---------------------------------------------------------------------* +*& Pattern: TYPE ... TABLE OF (typename) ... +*&---------------------------------------------------------------------* "Creating internal tables "Note that the syntax with CREATE DATA does not support the specification of @@ -1474,7 +1510,9 @@ DATA itab TYPE SORTED TABLE OF zdemo_abap_fli WITH UNIQUE KEY carrid connid flda DATA(key_table) = VALUE string_table( ( `CARRID` ) ( `CONNID` ) ( `FLDATE` ) ). CREATE DATA dref TYPE SORTED TABLE OF ('ZDEMO_ABAP_FLI') WITH UNIQUE KEY (key_table). -"----- Pattern: TYPE REF TO (typename) ----- +*&---------------------------------------------------------------------* +*& Pattern: TYPE REF TO (typename) +*&---------------------------------------------------------------------* "Creating data reference variables @@ -1483,23 +1521,31 @@ CREATE DATA dref TYPE REF TO ('T_C3'). CREATE DATA dref TYPE REF TO ('T_FLI_STRUC'). CREATE DATA dref TYPE REF TO ('T_CARR_TAB'). -"----- Pattern: TYPE LINE OF (typename) ----- +*&---------------------------------------------------------------------* +*& Pattern: TYPE LINE OF (typename) +*&---------------------------------------------------------------------* "Creating structures based on table types CREATE DATA dref TYPE LINE OF ('T_CARR_TAB'). -"----- Pattern: LIKE struc-(dobjname) ----- +*&---------------------------------------------------------------------* +*& Pattern: LIKE struc-(dobjname) +*&---------------------------------------------------------------------* CREATE DATA dref LIKE fli_struc-('CARRID'). -"----- Pattern: TYPE (absolute_name) ----- +*&---------------------------------------------------------------------* +*& Pattern: TYPE (absolute_name) +*&---------------------------------------------------------------------* CREATE DATA dref TYPE ('\TYPE=STRING'). "Getting an absolute type name; see more information further down DATA(absolute_name) = cl_abap_typedescr=>describe_by_name( 'ZDEMO_ABAP_CARR' )->absolute_name. CREATE DATA dref TYPE (absolute_name). -"----- Pattern: TYPE HANDLE type_description_object ----- +*&---------------------------------------------------------------------* +*& Pattern: TYPE HANDLE type_description_object +*&---------------------------------------------------------------------* "Getting a type description object. Find more information about RTTI below. DATA(tdo_elem) = cl_abap_elemdescr=>get_c( 4 ). "type c length 4 @@ -1706,9 +1752,9 @@ itab_ref = VALUE #( ( NEW demo_struct( col1 = 1 col2 = `aaa` col3 = `zzz` ) ) ). "- Many of the following statements provide similar additions offering dynamic " specifications, such as USING KEY and dynamic component name specifications. -"---------------------------------------------------------- -"------------------------ SORT (1) ------------------------ -"---------------------------------------------------------- +*&---------------------------------------------------------------------* +*& SORT (1) +*&---------------------------------------------------------------------* "Note: See more dynamic specifications with SORT statements "further down. @@ -1719,9 +1765,9 @@ SORT itab_ek BY (field_name) DESCENDING. "Unnamed data object specified within parenteses SORT itab_ek BY ('COL2') ASCENDING. -"------------------------------------------------------------- -"------------------------ READ TABLE ------------------------- -"------------------------------------------------------------- +*&---------------------------------------------------------------------* +*& READ TABLE +*&---------------------------------------------------------------------* "Reading by specifying keys dynamically "Implicitly specifying the table key values in a work area (USING KEY addition) @@ -1772,9 +1818,9 @@ DATA(dyn_where_cond_tab) = VALUE string_table( ( `col3` ) ( `CS` ) ( `'x'` ) ). READ TABLE itab INTO dyn_res WHERE (dyn_where_cond_tab). ASSERT sy-tabix = 3. -"------------------------------------------------------------- -"------------------------ Table expressions ------------------ -"------------------------------------------------------------- +*&---------------------------------------------------------------------* +*& Table expressions +*&---------------------------------------------------------------------* "Similar to READ TABLE statements, you can specify table lines with 3 alternatives: "index read, read using free key, table key @@ -1801,9 +1847,9 @@ DATA(wa_te4) = itab[ KEY ('PRIMARY_KEY') COMPONENTS ('COL1') = 1 ]. itab[ 1 ]-('COL2') = `jkl`. itab_ref[ 1 ]->('COL2') = `mno`. -"-------------------------------------------------------- -"------------------------ LOOP AT ----------------------- -"-------------------------------------------------------- +*&---------------------------------------------------------------------* +*& LOOP AT +*&---------------------------------------------------------------------* "USING KEY addition: Overriding the standard order determined by the table category LOOP AT itab REFERENCE INTO DATA(ref) USING KEY ('SK'). @@ -1828,9 +1874,9 @@ LOOP AT itab REFERENCE INTO ref WHERE (cond_loop). ... ENDLOOP. -"-------------------------------------------------------- -"------------------------ INSERT ------------------------ -"-------------------------------------------------------- +*&---------------------------------------------------------------------* +*& INSERT +*&---------------------------------------------------------------------* "The USING KEY addition (which accepts a dynamic specification) affects the order in which lines are inserted. @@ -1859,9 +1905,9 @@ LOOP AT itab INTO DATA(wa_pk) USING KEY ('PRIMARY_KEY'). APPEND wa_pk TO it_primekey_idx. ENDLOOP. -"-------------------------------------------------------- -"------------------------ MODIFY ------------------------ -"-------------------------------------------------------- +*&---------------------------------------------------------------------* +*& MODIFY +*&---------------------------------------------------------------------* "In the following example, a line is modified based on a work area and a table key. "The component col1 is left out from the work area intentionally. @@ -1881,9 +1927,9 @@ MODIFY itab INDEX 2 USING KEY ('SK') FROM VALUE #( col3 = `ttt` ) TRANSPORTING ( DATA(cond_mod) = `COL1 < 3`. MODIFY itab FROM VALUE #( col3 = `sss` ) TRANSPORTING ('COL3') WHERE (cond_mod). -"-------------------------------------------------------- -"------------------------ DELETE ------------------------ -"-------------------------------------------------------- +*&---------------------------------------------------------------------* +*& DELETE +*&---------------------------------------------------------------------* "A single line or multipled lines can be deleted. "Note that DELETE ADJACENT DUPLICATES statements can also be specified using @@ -1908,9 +1954,9 @@ DATA(condition_tab) = VALUE string_table( ( `COL1 < 3` ) ( `COL3 = ``www``` ) ). DELETE itab WHERE (condition_tab). -"-------------------------------------------------------- -"------------------------ SORT (2) ------------------------ -"-------------------------------------------------------- +*&---------------------------------------------------------------------* +*& SORT (2) +*&---------------------------------------------------------------------* "Sorting by dynamically specified components in a sort table, i. e.an "internal table of type abap_sortorder_tab. @@ -1995,7 +2041,9 @@ SORT it BY VALUE abap_sortorder_tab( FOR wa IN comp_names ( name = condense( to_ ### Dynamic ABAP SQL Statements ```abap -"--------------------- Dynamic SELECT list --------------------- +*&---------------------------------------------------------------------* +*& Dynamic SELECT list +*&---------------------------------------------------------------------* DATA(select_list) = `CARRID, CONNID, FLDATE`. DATA fli_tab TYPE TABLE OF zdemo_abap_fli WITH EMPTY KEY. @@ -2004,14 +2052,18 @@ SELECT (select_list) FROM zdemo_abap_fli INTO CORRESPONDING FIELDS OF TABLE @fli_tab. -"--------------------- Dynamic FROM clause --------------------- +*&---------------------------------------------------------------------* +*& Dynamic FROM clause +*&---------------------------------------------------------------------* DATA(table) = 'ZDEMO_ABAP_FLI'. SELECT * FROM (table) INTO TABLE @fli_tab. -"--------------------- Excursion: Compatible target data objects --------------------- +*&---------------------------------------------------------------------* +*& Excursion: Compatible target data objects +*&---------------------------------------------------------------------* "In the examples above, the data object/type is created statically. @@ -2041,7 +2093,9 @@ SELECT * FROM (table) INTO TABLE NEW @DATA(dref_tab). -"--------------------- Dynamic WHERE clause --------------------- +*&---------------------------------------------------------------------* +*& Dynamic WHERE clause +*&---------------------------------------------------------------------* "The example includes a WHERE clause that is created as an internal "table with a character-like row type. @@ -2062,14 +2116,18 @@ SELECT * WHERE (where_clause_string) INTO TABLE NEW @DATA(tab_dyn_where_str). -"--------------------- Dynamic ORDER BY clause --------------------- +*&---------------------------------------------------------------------* +*& 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 statement with miscellaneous dynamic specifications +*&---------------------------------------------------------------------* SELECT (`CARRID, CONNID, FLDATE`) FROM (`ZDEMO_ABAP_FLI`) @@ -2077,7 +2135,9 @@ SELECT (`CARRID, CONNID, FLDATE`) ORDER BY (`FLDATE`) INTO TABLE NEW @DATA(tab_dyn_misc). -"--------------------- Dynamic INSERT statement --------------------- +*&---------------------------------------------------------------------* +*& Dynamic INSERT statement +*&---------------------------------------------------------------------* "Creating a structure to be inserted into the database table SELECT SINGLE * @@ -2087,21 +2147,29 @@ dref_struc->('CARRID') = 'YZ'. INSERT (table) FROM @dref_struc->*. -"--------------------- Dynamic UPDATE statement --------------------- +*&---------------------------------------------------------------------* +*& Dynamic UPDATE statement +*&---------------------------------------------------------------------* dref_struc->('CURRENCY') = 'EUR'. UPDATE (table) FROM @dref_struc->*. -"--------------------- Dynamic MODIFY statement --------------------- +*&---------------------------------------------------------------------* +*& Dynamic MODIFY statement +*&---------------------------------------------------------------------* dref_struc->('SEATSOCC') = 10. MODIFY (table) FROM @dref_struc->*. -"--------------------- Dynamic DELETE statement --------------------- +*&---------------------------------------------------------------------* +*& Dynamic DELETE statement +*&---------------------------------------------------------------------* DELETE FROM (table) WHERE (`CARRID = 'YZ'`). -"--------------------- Dynamic UPDATE ... SET ... statement --------------------- +*&---------------------------------------------------------------------* +*& Dynamic UPDATE ... SET ... statement +*&---------------------------------------------------------------------* "Inserting demo data into the database table to work with TYPES carr_tab TYPE TABLE OF zdemo_abap_carr WITH EMPTY KEY. @@ -2130,7 +2198,9 @@ set_clause = `CURRCODE = 'EUR'`. UPDATE ('ZDEMO_ABAP_CARR') SET (set_clause) WHERE (where_cl). -"--------------------- Dynamic UPDATE ... INDICATORS ... statement --------------------- +*&---------------------------------------------------------------------* +*& Dynamic UPDATE ... INDICATORS ... statement +*&---------------------------------------------------------------------* "The statement changes values of specific fields without overwriting existing values of "other fields. @@ -2224,90 +2294,101 @@ CLASS zcl_demo_abap IMPLEMENTATION. "table is looped over to output content of all database tables DATA(dbtabs) = VALUE string_table( ( `ZDEMO_ABAP_CARR` ) ( `ZDEMO_ABAP_FLI` ) + ( `ZDEMO_WRONG_TABLE` ) ( `ZDEMO_ABAP_FLSCH` ) ). LOOP AT dbtabs INTO DATA(dbtab). - "Retrieving database content of a dynamically specified database table (up to 5 rows) + + "Checking for allowed input 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.| ). + DATA(value1) = cl_abap_dyn_prg=>check_allowlist( + val = dbtab + allowlist_str = `ZDEMO_ABAP_CARR,ZDEMO_ABAP_FLI,ZDEMO_ABAP_FLSCH` ). + + "Retrieving database content of a dynamically specified database table (up to 5 rows) + 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( sql_error->get_text( ) ). + CONTINUE. + ENDTRY. + CATCH cx_abap_not_in_allowlist INTO DATA(not_allowed). + out->write( not_allowed->get_text( ) ). + CONTINUE. 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). - out->write( |{ error->get_text( ) }| ). - ENDTRY. + "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). + out->write( |{ error->get_text( ) }| ). + 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 #( LET lv = |{ -(-name) }| IN - WHEN strlen( lv ) > len THEN strlen( lv ) - 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. + IF error IS INITIAL. out->write( |\n| ). - CLEAR: str, it_comps. + 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 #( LET lv = |{ -(-name) }| IN + WHEN strlen( lv ) > len THEN strlen( lv ) + 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. ENDLOOP. ENDMETHOD. ENDCLASS. @@ -2403,9 +2484,9 @@ CLASS zcl_demo_abap IMPLEMENTATION. DATA(cl_name) = `ZCL_DEMO_ABAP`. DATA(meth_name1) = `STAT_METH1`. - "------------------------------------------------------------------------ - "---------------- Calling static methods dynamically -------------------- - "------------------------------------------------------------------------ +*&---------------------------------------------------------------------* +*& Calling static methods dynamically +*&---------------------------------------------------------------------* "-------- Method without mandatory parameters defined -------- "The syntax is possible for methods of the same class. @@ -2464,9 +2545,9 @@ CLASS zcl_demo_abap IMPLEMENTATION. CATCH cx_sy_dyn_call_illegal_type. ENDTRY. - "------------------------------------------------------------------------ - "---------------- Calling instance methods dynamically ------------------ - "------------------------------------------------------------------------ +*&---------------------------------------------------------------------* +*& Calling instance methods dynamically +*&---------------------------------------------------------------------* "Creating an instance of a class by specifying the type dynamically DATA oref TYPE REF TO object. @@ -2488,9 +2569,9 @@ CLASS zcl_demo_abap IMPLEMENTATION. CALL METHOD oref->(`STAT_METH2`) EXPORTING text = `test` IMPORTING result = res. ASSERT res = `TEST`. - "------------------------------------------------------------------------ - "------------------- PARAMETER-TABLE addition --------------------------- - "------------------------------------------------------------------------ +*&---------------------------------------------------------------------* +*& PARAMETER-TABLE addition +*&---------------------------------------------------------------------* "------- Static equivalents to the dynamic statement below ------- DATA(oref_stat) = NEW zcl_demo_abap( ). @@ -2973,11 +3054,10 @@ CLASS zcl_demo_abap IMPLEMENTATION. "Filling demo database tables of the ABAP cheat sheet repository zcl_demo_abap_aux=>fill_dbtabs( ). - "-------------------------------------------------------------------- - "--- Specifying the data object holding external input as operand --- - "--- and literal ---------------------------------------------------- - "-------------------------------------------------------------------- - +*&-------------------------------------------------------------------------* +*& Specifying the data object holding external input as operand and literal +*&-------------------------------------------------------------------------* + "The example explores a dynamic WHERE clause. External content is used "in the WHERE clause, unchecked. @@ -3025,9 +3105,10 @@ CLASS zcl_demo_abap IMPLEMENTATION. out->write( |\n\n| ). out->write( |{ repeat( val = `*` occ = 70 ) }| ). - "-------------------------------------------------------------------- - "------------ Accessing not allowed database tables ----------------- - "-------------------------------------------------------------------- +*&---------------------------------------------------------------------* +*& Accessing not allowed database tables +*&---------------------------------------------------------------------* + "Assume the name of a database table is specified externally, and a "dynamic ABAP SQL statement uses this name. Potentially, users that "are actually not allowed to access the database table may get access. @@ -3103,9 +3184,9 @@ CLASS zcl_demo_abap IMPLEMENTATION. out->write( |\n\n| ). out->write( |{ repeat( val = `*` occ = 70 ) }| ). - "-------------------------------------------------------------------- - "------------ Verifying input against a given allowlist ------------ - "-------------------------------------------------------------------- +*&---------------------------------------------------------------------* +*& Verifying input against a given allowlist +*&---------------------------------------------------------------------* "Assume a SELECT statement dynamically specifies the column names "in the SELECT list. Table columns might be accessed although @@ -3150,9 +3231,9 @@ CLASS zcl_demo_abap IMPLEMENTATION. out->write( |\n\n| ). out->write( |{ repeat( val = `*` occ = 70 ) }| ). - "-------------------------------------------------------------------- - "------------ Potential manipulation of ABAP SQL clauses ------------ - "-------------------------------------------------------------------- +*&---------------------------------------------------------------------* +*& Potential manipulation of ABAP SQL clauses +*&---------------------------------------------------------------------* "In the following example, a dynamic WHERE clause is set up. For this, "it is assumed that the WHERE clause uses external input via input fields. @@ -3279,9 +3360,9 @@ CLASS zcl_demo_abap IMPLEMENTATION. out->write( |{ repeat( val = `*` occ = 70 ) }| ). - "-------------------------------------------------------------------- - "---------------------------- Escaping ------------------------------ - "-------------------------------------------------------------------- +*&---------------------------------------------------------------------* +*& Escaping +*&---------------------------------------------------------------------* "In various contexts, a replacement of special characters may be important. "Such an escaping is applied on characters contained in a string according @@ -4442,11 +4523,10 @@ They use the following methods to get type description objects: - `...=>get*` (getting type description objects for elementary and other types; other get* methods are shown further down) ```abap -"------------------------------------------------------------------ -"--- Getting a type description object from an existing data ------ -"--- type name ---------------------------------------------------- -"--- describe_by_name method -------------------------------------- -"------------------------------------------------------------------ +*&---------------------------------------------------------------------* +*& Getting a type description object from an existing data type name +*& describe_by_name method +*&---------------------------------------------------------------------* "Elementary and structured data object, internal table TYPES ty_elem TYPE c LENGTH 5. @@ -4459,11 +4539,10 @@ DATA(tdo_from_name2) = cl_abap_typedescr=>describe_by_name( type_name ). "As shown above, using a cast to get more details. DATA(tdo_from_name3) = CAST cl_abap_tabledescr( cl_abap_typedescr=>describe_by_name( 'TY_TAB' ) ). -"------------------------------------------------------------------ -"--- Getting a type description object from an existing data ------ -"--- object ------------------------------------------------------- -"--- describe_by_data method -------------------------------------- -"------------------------------------------------------------------ +*&---------------------------------------------------------------------* +*& Getting a type description object from an existing data object +*& describe_by_data method +*&---------------------------------------------------------------------* "Elementary and structured data object, internal table DATA elem_dobj TYPE c LENGTH 5. @@ -4475,11 +4554,10 @@ DATA(tdo_from_dobj2) = cl_abap_typedescr=>describe_by_data( struct_dobj ). "As shown above, using a cast to get more details. DATA(tdo_from_dobj3) = CAST cl_abap_tabledescr( cl_abap_typedescr=>describe_by_data( tab_dobj ) ). -"---------------------------------------------------------------- -"--- Getting a type description object for built-in elementary -- -"--- types ------------------------------------------------------ -"--- cl_abap_elemdescr=>get* methods ---------------------------- -"---------------------------------------------------------------- +*&---------------------------------------------------------------------* +*& Getting a type description object for built-in elementary types +*& cl_abap_elemdescr=>get* methods +*&---------------------------------------------------------------------* "Conceptually, all elementary, built-in ABAP types already "exist and can be accessed by the corresponding get_* methods. @@ -4957,7 +5035,7 @@ DATA(tdo_tab_4) = cl_abap_tabledescr=>get_with_keys( ( name = 'F' type = cl_abap_elemdescr=>get_i( ) ) ( name = 'G' type = CAST cl_abap_datadescr( cl_abap_typedescr=>describe_by_name( 'LAND1' ) ) ) ( name = 'H' type = CAST cl_abap_datadescr( cl_abap_typedescr=>describe_by_name( 'ZDEMO_ABAP_FLSCH' ) ) ) - ( name = 'I' type = CAST cl_abap_datadescr( CAST cl_abap_refdescr( cl_abap_typedescr=>describe_by_data( REF #( `hello` ) ) ) ) ) + ( name = 'I' type = CAST cl_abap_datadescr( cl_abap_refdescr=>get_by_name( 'STRING' ) ) ) ) ) p_keys = VALUE #( ( name = VALUE #( ) "In case of the primary table key, a name must be provided here diff --git a/07_String_Processing.md b/07_String_Processing.md index 3d25ec3..1baa0e8 100644 --- a/07_String_Processing.md +++ b/07_String_Processing.md @@ -347,7 +347,10 @@ ASSERT cl_abap_char_utilities=>cr_lf = |\r\n|. - The following syntax examples demonstrate a selection. For information about all options, refer to [this topic](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapcompute_string_format_options.htm) in the ABAP Keyword Documentation. ```abap -"---------------------- DATE ---------------------- +*&---------------------------------------------------------------------* +*& DATE +*&---------------------------------------------------------------------* + "Defining the format of a date "The output is just an example and depends on your settings. DATA(d) = |The date is { cl_abap_context_info=>get_system_date( ) DATE = USER }.|. "The date is 01/01/2024. @@ -355,7 +358,10 @@ d = |{ cl_abap_context_info=>get_system_date( ) DATE = RAW }|. "20240101 d = |{ cl_abap_context_info=>get_system_date( ) DATE = ISO }|. "2024-01-01 d = |{ cl_abap_context_info=>get_system_date( ) DATE = ENVIRONMENT }|. "01/01/2024 -"---------------------- TIME ---------------------- +*&---------------------------------------------------------------------* +*& TIME +*&---------------------------------------------------------------------* + "Defining the format of a time "The output is just an example and depends on your settings. DATA(tm) = |The time is { cl_abap_context_info=>get_system_time( ) TIME = ISO }.|. "The time is 14:37:24. @@ -363,7 +369,10 @@ tm = |{ cl_abap_context_info=>get_system_time( ) TIME = RAW }|. "143724 tm = |{ cl_abap_context_info=>get_system_time( ) TIME = USER }|. "14:37:24 tm = |{ cl_abap_context_info=>get_system_time( ) TIME = ENVIRONMENT }|. "14:37:24 -"---------------------- TIMESTAMP ---------------------- +*&---------------------------------------------------------------------* +*& TIMESTAMP +*&---------------------------------------------------------------------* + "Defining the format of a time stamp "The output is just an example and depends on your settings. DATA(ts) = |{ utclong_current( ) TIMESTAMP = SPACE }|. "2024-01-01 14:39:50.4069170 @@ -372,31 +381,49 @@ ts = |{ utclong_current( ) TIMESTAMP = USER }|. "01/01/2024 14:39:50.4072010 ts = |{ utclong_current( ) TIMESTAMP = ENVIRONMENT }|. "01/01/2024 14:39:50.4073230 ts = |{ utclong_current( ) }|. "2024-01-01 14:39:50.4074060 -"---------------------- TIMEZONE ---------------------- +*&---------------------------------------------------------------------* +*& TIMEZONE +*&---------------------------------------------------------------------* + "Defining the format of a time stamp using the rules for time zones DATA(tz) = |{ utclong_current( ) TIMEZONE = 'UTC' }|. "2024-12-30 14:43:20.6534640 tz = |{ utclong_current( ) TIMEZONE = 'CET' COUNTRY = 'DE ' }|. "30.12.2024 15:43:20,6536320 tz = |{ utclong_current( ) TIMEZONE = 'EST' COUNTRY = 'US ' }|. "12/30/2024 09:43:20.6889180 AM -"---------------------- CASE ---------------------- +*&---------------------------------------------------------------------* +*& CASE +*&---------------------------------------------------------------------* + "Lowercase and uppercase s1 = `AbCdEfG`. s2 = |{ s1 CASE = LOWER }|. "abcdefg s2 = |{ s1 CASE = UPPER }|. "ABCDEFG -"---------------------- WIDTH/ALIGN ---------------------- +*&---------------------------------------------------------------------* +*& WIDTH/ALIGN +*&---------------------------------------------------------------------* + s1 = `##`. s2 = |{ s1 WIDTH = 10 ALIGN = LEFT }<---|. "'## <---' s2 = |{ s1 WIDTH = 10 ALIGN = CENTER }<---|. "' ## <---' -"---------------------- PAD ---------------------- +*&---------------------------------------------------------------------* +*& PAD +*&---------------------------------------------------------------------* + "Used to pad any surplus places in the result with the specified character. s2 = |{ s1 WIDTH = 10 ALIGN = RIGHT PAD = `.` }<---|. "'........##<---' -"---------------------- DECIMALS ---------------------- +*&---------------------------------------------------------------------* +*& DECIMALS +*&---------------------------------------------------------------------* + s1 = |{ CONV decfloat34( - 1 / 3 ) DECIMALS = 3 }|. "'-0.333' -"---------------------- SIGN ---------------------- +*&---------------------------------------------------------------------* +*& SIGN +*&---------------------------------------------------------------------* + "Defining the format of the +/- sign when the string represented "by the embedded expression represents a numeric value "- left without space, no + @@ -412,12 +439,18 @@ s1 = |{ 1 SIGN = RIGHTPLUS }|. "1+ "- left without space, blank right for + s1 = |{ +1 SIGN = RIGHTSPACE }|. "1 -"---------------------- ZERO ---------------------- +*&---------------------------------------------------------------------* +*& ZERO +*&---------------------------------------------------------------------* + "Defining the format of the numeric value zero. "Only to be specified if the embedded expression has a numeric data type. s1 = |'{ 0 ZERO = NO }' and '{ 0 ZERO = YES }'|. "'' and '0' -"---------------------- XSD ---------------------- +*&---------------------------------------------------------------------* +*& XSD +*&---------------------------------------------------------------------* + "Formatting is applied to an embedded expression (elementary data types) in asXML format that is "assigned to its data type. Check the information in the ABAP Keyword Documentation about the asXML "mapping of elementary ABAP types. @@ -431,7 +464,10 @@ s1 = |{ dat XSD = YES }|. "2024-01-01 s1 = |{ tim XSD = YES }|. "12:34:56 s1 = |{ utc XSD = YES }|. "2024-01-01T13:51:38.57088Z -"---------------------- STYLE ---------------------- +*&---------------------------------------------------------------------* +*& STYLE +*&---------------------------------------------------------------------* + "Defining the style of decimal floating point numbers; "see the details in the ABAP Keyword Documentation. DATA(dcfl34) = CONV decfloat34( '-123.45600' ). @@ -451,7 +487,10 @@ s1 = |{ dcfl34 STYLE = SCALE_PRESERVING_SCIENTIFIC }|. "-1.2345600E+0002 "Technical format s1 = |{ dcfl34 STYLE = ENGINEERING }|. "-123.456E+00 -"---------------------- ALPHA ---------------------- +*&---------------------------------------------------------------------* +*& ALPHA +*&---------------------------------------------------------------------* + "Adds or removes leading zeros from strings of digits; the data type "must be string, c, or n "Adding leading zeros @@ -1897,7 +1936,10 @@ Examples: DATA(some_string) = `aa bb cc dd ee`. DATA(original_string) = some_string. -"---------------- Statements ---------------- +*&---------------------------------------------------------------------* +*& Statements +*&---------------------------------------------------------------------* + FIND ALL OCCURRENCES OF PCRE `\s` IN some_string RESULTS DATA(findings). *LINE OFFSET LENGTH SUBMATCHES *0 2 1 OFFSET LENGTH @@ -1914,12 +1956,17 @@ REPLACE ALL OCCURRENCES OF PCRE `\s` IN some_string WITH `#`. some_string = original_string. -"---------------- Classes ---------------- +*&---------------------------------------------------------------------* +*& Classes +*&---------------------------------------------------------------------* + "The result is the same as 'findings' DATA(regex_cl1) = cl_abap_regex=>create_pcre( pattern = `\s` )->create_matcher( text = some_string )->find_all( ). +*&---------------------------------------------------------------------* +*& Built-in Functions +*&---------------------------------------------------------------------* -"---------------- Built-in Functions ---------------- "2 DATA(find_first_occ) = find( val = some_string pcre = `\s` ). @@ -2459,11 +2506,13 @@ DATA off TYPE i. DATA(abc_str) = `abc def ghi jkl mno pqr stu vwx yz`. DATA(copy_str) = abc_str. -"----------------------------------------------------------------------------- -"------------------------ FIND and REPLACE statements ------------------------ -"----------------------------------------------------------------------------- +*&---------------------------------------------------------------------* +*& FIND and REPLACE statements +*&---------------------------------------------------------------------* -"------------------------ IN CHARACTER MODE addition ------------------------ +*&---------------------------------------------------------------------* +*& IN CHARACTER MODE addition +*&---------------------------------------------------------------------* "Searching for the first blank in the string "3 @@ -2494,7 +2543,9 @@ REPLACE ALL OCCURRENCES OF ` ` IN abc_str WITH `#` IN CHARACTER MODE. abc_str = copy_str. -"------------------------ IN BYTE MODE addition ------------------------ +*&---------------------------------------------------------------------* +*& IN BYTE MODE addition +*&---------------------------------------------------------------------* "Converting to xstring "6162632064656620676869206A6B6C206D6E6F20707172207374752076777820797A @@ -2524,9 +2575,9 @@ abc_xstr = copy_xstr. "6162632364656623676869236A6B6C236D6E6F23707172237374752376777823797A REPLACE ALL OCCURRENCES OF blank_xstr IN abc_xstr WITH repl_xstr IN BYTE MODE. -"----------------------------------------------------------------------------- -"--------------------------- CONCATENATE statements -------------------------- -"----------------------------------------------------------------------------- +*&---------------------------------------------------------------------* +*& CONCATENATE statements +*&---------------------------------------------------------------------* DATA(part_str1) = `abc`. DATA(part_str2) = `def`. @@ -2560,9 +2611,9 @@ CONCATENATE LINES OF xstr_table INTO DATA(concat_xstr_tab) IN BYTE MODE. "abcdef DATA(concat_xstr_tab_converted) = cl_abap_conv_codepage=>create_in( )->convert( concat_xstr_tab ). -"----------------------------------------------------------------------------- -"------------------------------- SHIFT statements ---------------------------- -"----------------------------------------------------------------------------- +*&---------------------------------------------------------------------* +*& SHIFT statements +*&---------------------------------------------------------------------* DATA(str) = `abcdef`. DATA(copy) = str. @@ -2582,9 +2633,9 @@ DATA(xstr) = cl_abap_conv_codepage=>create_out( )->convert( str ). "6263646566 SHIFT xstr IN BYTE MODE. -"----------------------------------------------------------------------------- -"------------------------------- SPLIT statements ---------------------------- -"----------------------------------------------------------------------------- +*&---------------------------------------------------------------------* +*& SPLIT statements +*&---------------------------------------------------------------------* str = `abc def`. diff --git a/08_EML_ABAP_for_RAP.md b/08_EML_ABAP_for_RAP.md index c702193..d10e13c 100644 --- a/08_EML_ABAP_for_RAP.md +++ b/08_EML_ABAP_for_RAP.md @@ -301,8 +301,8 @@ an ABAP program using ABAP EML (which this cheat sheet and the examples focus on - [Structure of a RAP behavior definition](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abencds_bdef.htm) - [Infos about BDL syntax](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenbdl_syntax.htm) - [Infos about behavior definitions](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenbdl.htm) + - [RAP BDL - Feature Tables](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/abenrap_feature_table.html) - The following example shows a commented BDEF, and is just an excursion. Note that there is a wide variety of possible specifications and options. The example shows only a selection. The example shows multiple specifications with comments and also syntax hidden with comments, just for the sake of showing more syntax options. For full details, correct specification and combination options, refer to the ABAP Keyword Documentation. For example, it is not possible to specify operations multiple times and more. ```js @@ -1013,7 +1013,7 @@ is only relevant in the context of [draft](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenbdl_with_draft.htm). -The following table covers a selection of available BDEF derived type components. Find more details on the available components in section [Components of BDEF Derived Types](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapderived_types_comp.htm). +The following table covers a selection of available BDEF derived type components. Find more details on the available components in section [Components of BDEF Derived Types](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapderived_types_comp.htm) of the ABAP Keyword Documentation. @@ -1105,7 +1105,7 @@ MODIFY ENTITIES OF zdemo_abap_rap_ro_m diff --git a/21_XML_JSON.md b/21_XML_JSON.md index 9478980..72fd82e 100644 --- a/21_XML_JSON.md +++ b/21_XML_JSON.md @@ -262,7 +262,9 @@ DATA(conv_string) = cl_abap_conv_codepage=>create_in( )->convert( xml_pa ). Creating XML data using sXML: ```abap -"--------------------- Token-based rendering ---------------------- +*&---------------------------------------------------------------------* +*& Token-based rendering +*&---------------------------------------------------------------------* "For sXML, there are specialized writer classes, such as CL_SXML_STRING_WRITE. "Writers created with this class render XML data to a byte string. @@ -322,7 +324,9 @@ DATA(xml) = CAST cl_sxml_string_writer( writer )->get_output( ). " " -"--------------------- Object-oriented rendering ---------------------- +*&---------------------------------------------------------------------* +*& Object-oriented rendering +*&---------------------------------------------------------------------* DATA(writer_oo) = CAST if_sxml_writer( cl_sxml_string_writer=>create( type = if_sxml=>co_xt_xml10 encoding = 'UTF-8' ) ). @@ -379,7 +383,9 @@ DATA(xml_oo) = CAST cl_sxml_string_writer( writer_oo )->get_output( ). Parsing XML data using sXML: ```abap -"--------------------- Token-based parsing ---------------------- +*&---------------------------------------------------------------------* +*& Token-based parsing +*&---------------------------------------------------------------------* "Creating demo XML data to be used in the example TRY. @@ -508,7 +514,9 @@ ENDTRY. *CO_NT_ELEMENT_CLOSE subnode3 *CO_NT_ELEMENT_CLOSE node -"--------------------- Object-oriented parsing ---------------------- +*&---------------------------------------------------------------------* +*& Object-oriented parsing +*&---------------------------------------------------------------------* "The example uses the XML from above CLEAR nodes_tab. @@ -693,7 +701,10 @@ ENDTRY. There are multiple options. Check the executable example to explore them. ```abap -"--------------------- Transforming XML data ---------------------- +*&---------------------------------------------------------------------* +*& Transforming XML data +*&---------------------------------------------------------------------* + "Options for src: "- Data object of type string or xstring containing XML data in XML 1.0 format "- Standard table with flat character-like or byte-like line type @@ -702,7 +713,10 @@ There are multiple options. Check the executable example to explore them. CALL TRANSFORMATION ... SOURCE XML src RESULT ... -"--------------------- Transforming ABAP data ---------------------- +*&---------------------------------------------------------------------* +*& Transforming ABAP data +*&---------------------------------------------------------------------* + "No XML specified after SOURCE "Options after SOURCE: "- One or multiple ABAP data objects (abap1 in the snippet) can be specified as @@ -725,7 +739,10 @@ CALL TRANSFORMATION ... SOURCE (srctab) There are multiple options. Check the executable example to explore them in action. ```abap -"--------------------- Transforming to XML data ---------------------- +*&---------------------------------------------------------------------* +*& Transforming to XML data +*&---------------------------------------------------------------------* + "Options for res: "- Data object of type string or xstring "- Data object declared inline (e.g. DATA(a) or FINAL(b)), which has then the type xstring @@ -734,7 +751,10 @@ There are multiple options. Check the executable example to explore them in acti CALL TRANSFORMATION ... SOURCE ... RESULT XML res. -"--------------------- Transforming to ABAP data ---------------------- +*&---------------------------------------------------------------------* +*& Transforming to ABAP data +*&---------------------------------------------------------------------* + "No XML specified after RESULT "Similar to above, multiple ABAP data objects can be specified as a static parameter list. CALL TRANSFORMATION ... SOURCE ... @@ -1346,10 +1366,16 @@ For more information, see the class documentation. Note that there are many addi ```abap DATA(some_table) = VALUE string_table( ( `aaa` ) ( `bbb` ) ( `ccc` ) ). -"--------- ABAP -> JSON --------- +*&---------------------------------------------------------------------* +*& ABAP -> JSON +*&---------------------------------------------------------------------* + DATA(abap_to_json) = /ui2/cl_json=>serialize( data = some_table ). -"--------- JSON -> ABAP --------- +*&---------------------------------------------------------------------* +*& JSON -> ABAP +*&---------------------------------------------------------------------* + DATA json_to_abap_table TYPE string_table. /ui2/cl_json=>deserialize( EXPORTING json = abap_to_json CHANGING data = json_to_abap_table ). diff --git a/23_Date_and_Time.md b/23_Date_and_Time.md index 1960733..86b6747 100644 --- a/23_Date_and_Time.md +++ b/23_Date_and_Time.md @@ -131,7 +131,10 @@ DATA(tz_w_xco_utc) = xco_cp_time=>time_zone->utc->value. To retrieve the current date, you can, for example, use the `get_system_date` method of the `cl_abap_context_info` class. You can also use the [XCO library](https://help.sap.com/docs/btp/sap-business-technology-platform/xco-library?version=Cloud). ```abap -"--------------------- Retrieving the current date -------------------- +*&---------------------------------------------------------------------* +*& Retrieving the current date +*&---------------------------------------------------------------------* + "Retrieving the current date with respect to UTC, e.g. 20240101 "The result's base type is the DDIC type dats that is mapped to the "ABAP type d. @@ -171,7 +174,10 @@ DATA(date_utc_tz) = xco_cp=>sy->date( xco_cp_time=>time_zone->utc )->as( xco_cp_time=>format->iso_8601_basic )->value. -"--------------------- Retrieving current date values (XCO) -------------------- +*&---------------------------------------------------------------------* +*& Retrieving the current date values using XCO +*&---------------------------------------------------------------------* + "e.g. 01 DATA(day) = xco_cp=>sy->date( )->day. "e.g. 01 @@ -179,7 +185,10 @@ DATA(month) = xco_cp=>sy->date( )->month. "e.g. 2024 DATA(year) = xco_cp=>sy->date( )->year. -"--------------------- Creating dates -------------------- +*&---------------------------------------------------------------------* +*& Creating dates +*&---------------------------------------------------------------------* + DATA date_cr1 TYPE d. date_cr1 = '20240101'. DATA date_cr2 TYPE d VALUE '20240202'. @@ -338,7 +347,9 @@ DATA(weekday2) = ( 5 + date_calc_3 MOD 7 ) MOD 7 + 1. "6 (Saturday) DATA(date_w_first_day_of_month) = CONV d( replace( val = `202403020` off = 6 len = 2 with = `01` ) ). "20240301 DATA(date_w_last_day_of_prev_month) = CONV d( date_w_first_day_of_month - 1 ). "20240229 -"------------ Performing date additions and subtractions using the XCO library ------------ +*&---------------------------------------------------------------------* +*& Performing date additions and subtractions using the XCO library +*&---------------------------------------------------------------------* "Adding days to the current date using the 'add' method "e.g. 2024-03-16 (if the current date is 2024-03-11) @@ -498,7 +509,9 @@ The code snippet below provides examples of time processing, such as retrieving ### Retrieving the Current Time ```abap -"--------------------- Retrieving the current time -------------------- +*&---------------------------------------------------------------------* +*& Retrieving the current time +*&---------------------------------------------------------------------* "Retrieving the current time in UTC, e.g. 152450 DATA(utc_time) = cl_abap_context_info=>get_system_time( ). @@ -541,8 +554,6 @@ DATA(time_utc_tz) = xco_cp=>sy->time( xco_cp_time=>time_zone->utc ### Accessing Time Values ```abap -"--------------------- Accessing time values -------------------- - "Note: As mentioned in a previous section on dates, the access to time fields "works similar as date fields. As an example, seconds, minutes, and hours are "extracted from a time field. @@ -573,8 +584,6 @@ DATA(hr_w_xco) = xco_cp=>sy->time( xco_cp_time=>time_zone->user )->hour. ### Creating Time Values ```abap -"--------------------- Creating times -------------------- - DATA time_cr1 TYPE t. time_cr1 = '095812'. DATA time_cr2 TYPE t VALUE '112400'. @@ -598,7 +607,9 @@ DATA(seconds_from_time) = xco_time->second. "05 ### Performing Time Calculations ```abap -"------------ Performing time calculations ------------ +*&---------------------------------------------------------------------* +*& Performing time calculations +*&---------------------------------------------------------------------* "Retrieving seconds, minutes, and hours from a time value in a data object "of type t @@ -623,7 +634,9 @@ DATA(time_xco_subtr) = xco_cp=>sy->time( xco_cp_time=>time_zone->user )->as( xco_cp_time=>format->iso_8601_extended )->value. -"------------ Calculating the time delta between two time values ------------ +*&---------------------------------------------------------------------* +*& Calculating the time delta between two time values +*&---------------------------------------------------------------------* DATA: time1 TYPE t VALUE '210000', time2 TYPE t VALUE '040000'. @@ -647,7 +660,10 @@ DATA(time2_conv2i) = CONV i( time2 ). ASSERT time2_conv2i = ( 04 * 3600 ) + ( 00 * 60 ) + 00. ASSERT time2_conv2i - time1_conv2i = time_diff. -"---- Calculating the total values of the time difference in seconds, minutes and hours ---- +*&----------------------------------------------------------------------------------* +*& Calculating the total values of the time difference in seconds, minutes and hours +*&----------------------------------------------------------------------------------* + "The MOD operator is used and works in a way that the positive remainder "of the division of the left operand by the right is returned. Therefore, "it is irrelevant whether the time difference value is either positive or @@ -730,8 +746,6 @@ DATA(hours_no_div_dec) = CONV decfloat34( ( ( time2 - time1 ) MOD 86400 ) / 3600 ### CL_ABAP_TIMEFM: Converting Time Values ```abap -"------------ Conversions with the CL_ABAP_TIMEFM class ------------ - "Using the CL_ABAP_TIMEFM class, you can perform conversions with external "and internal representations of a time, e.g. conversion of a time in a data "object of type string to type t and vice versa. Multiple methods are available, @@ -825,7 +839,9 @@ DATA(ts_utc_tz) = xco_cp=>sy->moment( xco_cp_time=>time_zone->utc #### Creating/Modifying a Time Stamp ```abap -"--------------------- Creating time stamps -------------------- +*&---------------------------------------------------------------------* +*& Creating time stamps +*&---------------------------------------------------------------------* DATA ts7 TYPE utclong. ts7 = utclong_current( ). @@ -844,7 +860,9 @@ DATA(ts10) = xco_cp_time=>moment( iv_year = '2024' )->as( xco_cp_time=>format->iso_8601_extended )->value. -"--------------------- Modifying time stamps (XCO) -------------------- +*&---------------------------------------------------------------------* +*& Modifying time stamps (XCO) +*&---------------------------------------------------------------------* "As covered for date and time types, you can modify time stamps using string "processing functionalities. They are not covered here. XCO provides, for diff --git a/27_Exceptions.md b/27_Exceptions.md index aa7102d..5cc9078 100644 --- a/27_Exceptions.md +++ b/27_Exceptions.md @@ -276,9 +276,9 @@ Syntax examples for raising exceptions programmatically: > More variants of the statements shown are possible. They are covered in a [separate section below](#syntax-variants-of-raise-exceptionthrow) because they relate to topics covered in the following sections. ```abap -"------------------------------------------------------------------- -"----------------- RAISE EXCEPTION statements ---------------------- -"------------------------------------------------------------------- +*&---------------------------------------------------------------------* +*& RAISE EXCEPTION statements +*&---------------------------------------------------------------------* "RAISE EXCEPTION statement with the TYPE addition, specifying "the name of a visible exception class; an exception @@ -307,9 +307,9 @@ DATA dyn_exc TYPE REF TO cx_root. CREATE OBJECT dyn_exc TYPE ('CX_SY_ZERODIVIDE'). RAISE EXCEPTION dyn_exc. -"------------------------------------------------------------------- -"----------- COND/SWITCH operators with THROW addition ------------- -"------------------------------------------------------------------- +*&---------------------------------------------------------------------* +*& COND/SWITCH operators with THROW addition +*&---------------------------------------------------------------------* "THROW addition in conditional expressions with the COND and SWITCH operators "enabling raising class-based exceptions in operand positions @@ -651,9 +651,10 @@ DO 2 TIMES. ENDTRY. ENDDO. -"---------------------------------------------------------------------------- -"----------------------- INTO addition -------------------------------------- -"---------------------------------------------------------------------------- +*&---------------------------------------------------------------------* +*& INTO addition +*&---------------------------------------------------------------------* + "The example is the same as above. Here, the CLEANUP statement is specified "with the addition INTO. If required, you can evaluate the exception information "as shown above. @@ -785,9 +786,10 @@ CLASS zcl_demo_abap IMPLEMENTATION. METHOD if_oo_adt_classrun~main. - "---------------------------------------------------------------------------- - "----------------------- CATCH BEFORE UNWIND ------------------------------- - "---------------------------------------------------------------------------- +*&---------------------------------------------------------------------* +*& CATCH BEFORE UNWIND +*&---------------------------------------------------------------------* + "Example using the method "The following example creates a table containing integers from -5 to 5. This "table is looped across to have different values for divisions. Here, this @@ -983,9 +985,9 @@ msgv4 = sy-msgv4. "H > - In the executable example, `zcx_demo_abap_error_a` implements the `IF_T100_MESSAGE` interface and `zcx_demo_abap_error_b` implements `IF_T100_DYN_MSG`. ```abap -"---------------------------------------------------------------------------- -"------------------- RAISE EXCEPTION statements ---------------------------- -"---------------------------------------------------------------------------- +*&---------------------------------------------------------------------* +*& RAISE EXCEPTION statements +*&---------------------------------------------------------------------* "Multiple additions and variants are possible. The following examples "demonstrate a selection. @@ -1101,9 +1103,10 @@ RAISE EXCEPTION TYPE zcx_demo_abap_error_b MESSAGE ID sy-msgid NUMBER sy-msgno WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4. -"---------------------------------------------------------------------------- -"------------------- COND operator, THROW addition ------------------------- -"---------------------------------------------------------------------------- +*&---------------------------------------------------------------------* +*& COND operator, THROW addition +*&---------------------------------------------------------------------* + DATA(flag) = 'X'. "Specifying the exception class after THROW including a mandatory pair of parentheses @@ -1151,9 +1154,10 @@ MESSAGE e005(zdemo_abap_messages) WITH 'Some message' INTO DATA(msg6). DATA(cond_w_throw_8) = COND #( WHEN flag IS INITIAL THEN `works` ELSE THROW zcx_demo_abap_error_b( USING MESSAGE ) ). -"---------------------------------------------------------------------------- -"------------------- SWITCH operator, THROW addition ---------------------- -"---------------------------------------------------------------------------- +*&---------------------------------------------------------------------* +*& SWITCH operator, THROW addition +*&---------------------------------------------------------------------* + DATA(switch_w_throw_1) = SWITCH #( flag WHEN '' THEN `works` ELSE THROW zcx_demo_abap_error_a( ) ). diff --git a/28_Regular_Expressions.md b/28_Regular_Expressions.md index 44d53cb..527e2f7 100644 --- a/28_Regular_Expressions.md +++ b/28_Regular_Expressions.md @@ -819,9 +819,9 @@ string_cond_pattern = replace( val = `cd` pcre = `(ab)?cd` with = `${1:-yz}cd` ) The following example demonstrates a selection of syntax options with `FIND` and `REPLACE`. There are multiple options as there is a rich variety of additions. For more details, refer to the [String Processing](07_String_Processing.md) cheat sheet. ```abap -"----------------------------------------------------------------------------- -"------------------------------- FIND ---------------------------------------- -"----------------------------------------------------------------------------- +*&---------------------------------------------------------------------* +*& FIND +*&---------------------------------------------------------------------* DATA(str) = `Cathy's black cat on the mat played with Matt.`. @@ -943,9 +943,9 @@ ASSERT url_parts = url_parts_for_loop. *abap-concepts *controlled-sap-luw -"----------------------------------------------------------------------------- -"------------------------------- REPLACE ------------------------------------- -"----------------------------------------------------------------------------- +*&---------------------------------------------------------------------* +*& REPLACE +*&---------------------------------------------------------------------* DATA(str_replace) = `ab apppc app`. DATA(str_replace_copy) = str_replace. diff --git a/29_Numeric_Operations.md b/29_Numeric_Operations.md index 03e5e0a..5223b0c 100644 --- a/29_Numeric_Operations.md +++ b/29_Numeric_Operations.md @@ -30,7 +30,7 @@ This cheat sheet explores various aspects of numeric operations and calculations - Calculations use numeric data objects or those convertible to numeric types. - ABAP supports specific elementary numeric data types. - These types have distinct characteristics and value ranges, allowing the use for various purposes. -- This cheat sheet covers only [built-in ABAP types](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenbuiltin_abap_type_glosry.htm). [Built-in DDIC types](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenbuiltin_ddic_type_glosry.htm) are also available for defining types in the [ABAP Dictionary DDIC)](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenabap_dictionary_glosry.htm) and ABAP CDS. These types cannot be used directly in ABAP programs except for typed literals. They are mapped to built-in ABAP types; for example, the DDIC type `INT4` is mapped to type `i`, and `DECFLOAT16` is mapped to the built-in ABAP type `decfloat16`. +- This cheat sheet covers only [built-in ABAP types](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenbuiltin_abap_type_glosry.htm). [Built-in DDIC types](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenbuiltin_ddic_type_glosry.htm) are also available for defining types in the [ABAP Dictionary (DDIC)](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenabap_dictionary_glosry.htm) and ABAP CDS. These types cannot be used directly in ABAP programs except for typed literals. They are mapped to built-in ABAP types; for example, the DDIC type `INT4` is mapped to type `i`, and `DECFLOAT16` is mapped to the built-in ABAP type `decfloat16`. - Most types' values (except type `i`) cannot be directly specified in the program and must be represented by character literals interpretable as the respective type.
-The code snippet visualizes various specification options regarding `%key` and `%tky` as component groups, emphasizing how contained component may be accessed and that these component groups can contain further component groups. +The code snippet visualizes various specification options regarding `%key` and `%tky` as component groups, emphasizing how contained components may be accessed and that these component groups can contain further component groups. ``` abap MODIFY ENTITY zdemo_abap_rap_ro_m diff --git a/13_Program_Flow_Logic.md b/13_Program_Flow_Logic.md index 1c6a129..ef1e241 100644 --- a/13_Program_Flow_Logic.md +++ b/13_Program_Flow_Logic.md @@ -448,7 +448,10 @@ The following ABAP keywords are available for interrupting and exiting loops: | [`EXIT`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapexit_loop.htm) | `EXIT.` | The loop is terminated completely. The program flow resumes after the closing statement of the loop. | ```abap -"------------ CONTINUE ------------ +*&---------------------------------------------------------------------* +*& CONTINUE +*&---------------------------------------------------------------------* + DATA str_c TYPE string. DO 15 TIMES. "Continue with the next loop pass if the number is even @@ -462,7 +465,10 @@ DO 15 TIMES. ENDDO. "str_c: 1, 3, 5, 7, 9, 11, 13, 15 -"------------ CHECK ------------ +*&---------------------------------------------------------------------* +*& CHECK +*&---------------------------------------------------------------------* + DATA str_d TYPE string. DO 15 TIMES. "Terminating the loop pass and continuing with the next loop pass if the condition is @@ -481,7 +487,10 @@ DO 15 TIMES. ENDDO. "str_e: 1, 3, 5, 7, 9, 11, 13, 15 -"------------ EXIT ------------ +*&---------------------------------------------------------------------* +*& EXIT +*&---------------------------------------------------------------------* + DATA str_f TYPE string. DO 15 TIMES. "Terminating the entire loop @@ -636,7 +645,9 @@ TRY. ... ENDTRY. -"---------- Dynamic function method calls ---------- +*&---------------------------------------------------------------------* +*& Dynamic function method calls +*&---------------------------------------------------------------------* "Function module name contained in a variable DATA(func_name) = 'SOME_FUNCTION_MODULE_C'. @@ -791,7 +802,9 @@ CLASS zcl_demo_abap_func_test IMPLEMENTATION. out->write( calculation_result_table ). out->write( |\n\n\n| ). - "----- Dynamic function module call ---- +*&---------------------------------------------------------------------* +*& Dynamic function module call +*&---------------------------------------------------------------------* DATA(func_name) = 'Z_DEMO_ABAP_TEST_FUNC_M'. DATA(ptab) = VALUE abap_func_parmbind_tab( ( name = 'NUM1' diff --git a/16_Data_Types_and_Objects.md b/16_Data_Types_and_Objects.md index 3498686..bc98140 100644 --- a/16_Data_Types_and_Objects.md +++ b/16_Data_Types_and_Objects.md @@ -1822,7 +1822,10 @@ SELECT * [`FINAL`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenfinal_inline.htm). ```abap -"--------------------- Constants -------------------- +*&---------------------------------------------------------------------* +*& Constants +*&---------------------------------------------------------------------* + "As mentioned above, constants cannot be changed at runtime. CONSTANTS con_str TYPE string VALUE `hallo`. @@ -1836,7 +1839,10 @@ CONSTANTS: BEGIN OF const_struct, char TYPE c LENGTH 4 VALUE 'ABAP', END OF const_struct. -"--------------------- Immutable variables -------------------- +*&---------------------------------------------------------------------* +*& Immutable variables +*&---------------------------------------------------------------------* + FINAL(do_final_inl) = 1. DATA(do_data_inl) = 1 + do_final_inl. "not possible @@ -2292,7 +2298,9 @@ See the conversion rules for the different data types here: [Assignment and Conv ```abap -"-------------------- Conversions -------------------- +*&---------------------------------------------------------------------* +*& Conversions +*&---------------------------------------------------------------------* "Implicit conversions of the types c and string DATA do_1_str TYPE string VALUE `abcdef`. @@ -2317,7 +2325,9 @@ DATA(do_7_i) = CONV i( do_6_dcfl34 ). "`10-` DATA(i2str) = CONV string( -10 ). -"-------------------- Compatibility -------------------- +*&---------------------------------------------------------------------* +*& Compatibility +*&---------------------------------------------------------------------* "1. Source and target are compatible, all technical type properties " match diff --git a/17_SAP_LUW.md b/17_SAP_LUW.md index 22cd77a..a77c88b 100644 --- a/17_SAP_LUW.md +++ b/17_SAP_LUW.md @@ -329,7 +329,10 @@ Example using `CL_ABAP_TX`: ```abap ... -"------------- Activating the modify transactional phase ------------- +*&---------------------------------------------------------------------* +*& Activating the modify transactional phase +*&---------------------------------------------------------------------* + cl_abap_tx=>modify( ). "The following database modification statement is not allowed in the @@ -343,7 +346,10 @@ MODIFY zdemo_abap_carr FROM TABLE @( VALUE #( ... -"------------- Activating the save transactional phase ------------- +*&---------------------------------------------------------------------* +*& Activating the save transactional phase +*&---------------------------------------------------------------------* + cl_abap_tx=>save( ). "In this phase, database modifications are allowed. diff --git a/20_Selection_Screens_Lists.md b/20_Selection_Screens_Lists.md index 725c1b3..feaefe9 100644 --- a/20_Selection_Screens_Lists.md +++ b/20_Selection_Screens_Lists.md @@ -4322,7 +4322,6 @@ Overwriting line content and format

- Overwrites a line stored in the list buffer with the content of the `sy-lisel` system field - Allows additional modifications such as changing the value and format. - Find more information [here](https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abapmodify_line.htm). --
diff --git a/31_WHERE_Conditions.md b/31_WHERE_Conditions.md index ae946ba..37c33e9 100644 --- a/31_WHERE_Conditions.md +++ b/31_WHERE_Conditions.md @@ -10,6 +10,10 @@ This cheat sheet focuses on `WHERE` conditions and explores various syntax options in ABAP statements that include `WHERE` for data filtering. This is relevant, for example, when retrieving data from a data source using ABAP SQL or when processing internal tables with ABAP statements. For all details and syntax options, refer to the [ABAP Keyword Documentation](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/ABENABAP.html). Several aspects and code snippets in this cheat sheet are also available in other cheat sheets. +> **💡 Note**
+> - Most examples in the cheat sheet use internal tables as data sources for ABAP SQL `SELECT` statements to have self-contained examples. Use `SELECT` with internal tables as data sources only when SQL functionalities like joins exceed ABAP statements. For more details, refer to the [Internal Tables](01_Internal_Tables.md) cheat sheet. +> - Some examples also use artifacts from the ABAP cheat sheet repository. To check out these examples, ensure you have imported the ABAP cheat sheet repository into your system. +

⬆️ back to top

## WHERE Conditions in ABAP SQL Statements @@ -626,7 +630,7 @@ To try the example out, create a demo class named `zcl_demo_abap` and paste the > **💡 Note**
> - Many ABAP SQL `SELECT` statements in the example use an internal table as the data source to work with simple data. -> - Some examples also use subqueries. In these cases, another internal table cannot serve as the data source in the subquery. Therefore, examples use demo database tables from the ABAP cheat repository. They are also used to demonstrate `IS [NOT] NULL`. As a prerequisite, you have imported the ABAP cheat sheet repository to run the example class. +> - Some examples also use subqueries. In these cases, another internal table cannot currently serve as the data source in the subquery. Therefore, examples use demo database tables from the ABAP cheat repository. They are also used to demonstrate `IS [NOT] NULL`. As a prerequisite, you have imported the ABAP cheat sheet repository to run the example class. ```abap diff --git a/README.md b/README.md index 679ee4e..4c49276 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ ABAP cheat sheets[^1] ... - are enriched by links to glossary entries and chapters of the **ABAP Keyword Documentation** (the *F1 help*) and more for you to deep dive into the respective ABAP topics and get more comprehensive information.
-💡 Note +🟢 Click to expand for more information
- Since the ABAP cheat sheets provide information in a nutshell, they do not claim to be fully comprehensive as far as the described syntax and concepts are concerned. If you need more details, you can always consult the ABAP Keyword Documentation, for example, by choosing *F1* on a keyword in your code, or by searching directly using the online or the system-internal version. @@ -54,6 +54,7 @@ ABAP cheat sheets[^1] ... - The code snippets in the ABAP cheat sheet documents and the executable examples include many comments. While it is generally not recommended to overuse comments in your code, they are used here to explain and provide context directly where it is needed. In many cases, they illustrate the results of ABAP statements. - As previously mentioned, the cheat sheet documents and examples primarily focus on syntax options. Most of the executable examples, code snippets, names of data objects, classes, methods, interfaces, etc., are nonsemantic. - Many ABAP statements allow additions in various orders, and these orders are not always fixed. +