From 492b801c6abf946846fe4254474d3bd31f229528 Mon Sep 17 00:00:00 2001
From: danrega <16720986+danrega@users.noreply.github.com>
Date: Thu, 8 Aug 2024 16:39:50 +0200
Subject: [PATCH] Update
---
01_Internal_Tables.md | 287 ++++++++++++++++++++----------
03_ABAP_SQL.md | 321 +++++++++++++++++++++++++++++++++-
04_ABAP_Object_Orientation.md | 10 +-
06_Dynamic_Programming.md | 25 ++-
08_EML_ABAP_for_RAP.md | 22 ++-
21_XML_JSON.md | 10 +-
6 files changed, 558 insertions(+), 117 deletions(-)
diff --git a/01_Internal_Tables.md b/01_Internal_Tables.md
index d28071c..72d94dc 100644
--- a/01_Internal_Tables.md
+++ b/01_Internal_Tables.md
@@ -39,8 +39,8 @@
- [Iteration Expressions](#iteration-expressions)
- [Interrupting and Exiting Loops](#interrupting-and-exiting-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](#internal-tables-as-target-data-objects)
- - [Querying from Internal Tables](#querying-from-internal-tables)
+ - [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)
- [Sorting Internal Tables](#sorting-internal-tables)
- [Modifying Internal Table Content](#modifying-internal-table-content)
- [Deleting Internal Table Content](#deleting-internal-table-content)
@@ -2264,6 +2264,17 @@ ENDLOOP.
LOOP AT it REFERENCE INTO DATA(dref_inl).
...
ENDLOOP.
+
+"Table key specification (snippet uses example table from above)
+"The specified table key affects the order in which the table lines
+"are accessed and the evaluation of the other conditions.
+
+LOOP AT it INTO wa USING KEY primary_key.
+"LOOP AT it INTO wa USING KEY pk. "primary key alias
+"LOOP AT it INTO wa USING KEY sec_key. "secondary key
+"LOOP AT it INTO wa USING KEY sk. "secondary key alias
+ ...
+ENDLOOP.
```
- The order in which tables are iterated depends on the table category.
@@ -2313,17 +2324,6 @@ ENDLOOP.
LOOP AT it TRANSPORTING NO FIELDS WHERE a < 5.
...
ENDLOOP.
-
-"Table key specification (snippet uses example table from above)
-"The specified table key affects the order in which the table lines
-"are accessed and the evaluation of the other conditions.
-
-LOOP AT it INTO wa USING KEY primary_key.
-"LOOP AT it INTO wa USING KEY pk. "primary key alias
-"LOOP AT it INTO wa USING KEY sec_key. "secondary key
-"LOOP AT it INTO wa USING KEY sk. "secondary key alias
- ...
-ENDLOOP.
```
⬆️ back to top
@@ -2407,21 +2407,7 @@ ASSERT tabix = 5.
## Operations with Internal Tables Using ABAP SQL SELECT Statements
-- 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 ABAP SQL is executed in this buffer on the ABAP server, not directly on the database.
-
-So, ABAP SQL `SELECT` statements can be used for multiple purposes also on internal tables. The following snippets cover a selection. Find more details in the ABAP Keyword Documentation and in the [ABAP SQL cheat sheet](03_ABAP_SQL.md).
-
-> **💡 Note**
-> - No deep components (nested tables, strings) are allowed.
-> - Trailing blanks of short text fields are truncated.
-> - When joining multiple internal tables, it must be ensured that the ABAP SQL engine can handle it, which means only internal tables are used (no buffered database tables), no special features like hierarchies, aggregates, subselects, etc. are used.
-
-⬆️ back to top
-
-### Internal Tables as Target Data Objects
+### 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),
@@ -2502,77 +2488,198 @@ ENDIF.
⬆️ back to top
-### Querying from Internal Tables
-In `SELECT` statements, internal tables can also be used as data sources.
-The snippet shows adding multiple lines from an internal table to another internal table using `SELECT`. Note the alias name that must be defined for the internal table.
+### SELECT Queries with Internal Tables as Data Sources
-``` abap
-SELECT comp1, comp2, ...
- FROM @itab AS it_alias
- INTO TABLE @DATA(itab_sel).
-```
+- You can use internal tables as data sources in `SELECT` statements.
-Using the `LIKE` addition in the `WHERE` clause to extract internal table entries matching a specific pattern.
-```abap
-TYPES: BEGIN OF s,
- a TYPE c LENGTH 3,
- b TYPE i,
- END OF s,
- tab_type TYPE TABLE OF s WITH EMPTY KEY.
-DATA(itab) = VALUE tab_type( ( a = 'abc' b = 1 ) ( a = 'zbc' b = 2 )
- ( a = 'bde' b = 3 ) ( a = 'yde' b = 4 ) ).
+ ``` 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.
-SELECT a, b
- FROM @itab AS it_alias
- WHERE a LIKE '%bc'
- INTO TABLE @DATA(itab_sel_like).
+Notes and restrictions:
-*A B
-*abc 1
-*zbc 2
-```
+- 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`.
+- 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.
-Using the `IN` addition in the `WHERE` clause to extract internal table entries based on values specified in an operand list.
-```abap
-SELECT a, b
- FROM @itab AS it_alias
- WHERE a IN ('bde', 'yde', 'zde')
- INTO TABLE @DATA(itab_in).
+The following example explores various `SELECT` queries with internal tables as data sources. To try it out, create a demo class named `zcl_some_class` 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.
-*A B
-*bde 3
-*yde 4
-```
-
-Combining data from multiple internal 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"). See above.
+Example:
```abap
-TYPES: BEGIN OF s,
- a TYPE c LENGTH 3,
- b TYPE c LENGTH 3,
- c TYPE i,
- END OF s,
- tab_type TYPE TABLE OF s WITH EMPTY KEY.
-
-DATA(it1) = VALUE tab_type( ( a = 'aaa' b = 'bbb' c = 1 )
- ( a = 'ccc' b = 'ddd' c = 1 )
- ( a = 'eee' b = 'fff' c = 2 ) ).
+CLASS zcl_some_class DEFINITION
+ PUBLIC
+ FINAL
+ CREATE PUBLIC .
-DATA(it2) = VALUE tab_type( ( a = 'ggg' b = 'hhh' c = 1 )
- ( a = 'iii' b = 'jjj' c = 1 )
- ( a = 'kkk' b = 'lll' c = 3 ) ).
+ PUBLIC SECTION.
+ INTERFACES if_oo_adt_classrun.
+ PROTECTED SECTION.
+ PRIVATE SECTION.
-SELECT it_alias1~a, it_alias2~b
- FROM @it1 AS it_alias1
- INNER JOIN @it2 AS it_alias2 ON it_alias1~c = it_alias2~c
- INTO TABLE @DATA(it_join_result).
-
-*A B
-*aaa hhh
-*aaa jjj
-*ccc hhh
-*ccc jjj
+ENDCLASS.
+
+
+
+CLASS zcl_some_class 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
+ "enginge. 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
@@ -3094,7 +3201,7 @@ ENDCLASS.
The following example creates two demo internal tables. One without a secondary
table key and the other with a secondary table key. Consider a scenario where you
-have an internal table without a secondary table key, and you want to add a secondary table key later to improve read performance. The tables are populated with a lot of data. Then, in a `DO` loop, many reads are performed on the internal tables. One example uses a free key for the read, the other uses a secondary table key that includes the components used for the free key search. Before and after the reads, the current timestamp is stored in variables, from which the elapsed time is calculated. There should be a significant delta of the elapsed time.
+have a standard internal table without a secondary table key, and you want to add a secondary table key later to improve read performance. The tables are populated with a lot of data. Then, in a `DO` loop, many reads are performed on the internal tables. One example uses a free key for the read, the other uses a secondary table key that includes the components used for the free key search. Before and after the reads, the current timestamp is stored in variables, from which the elapsed time is calculated. There should be a significant delta of the elapsed time.
```abap
CLASS zcl_some_class DEFINITION PUBLIC FINAL CREATE PUBLIC.
diff --git a/03_ABAP_SQL.md b/03_ABAP_SQL.md
index d05c078..a9dce9c 100644
--- a/03_ABAP_SQL.md
+++ b/03_ABAP_SQL.md
@@ -8,6 +8,7 @@
- [Retrieving Data Using SELECT](#retrieving-data-using-select)
- [Basic Syntax](#basic-syntax)
- [SELECT List Variants](#select-list-variants)
+ - [Data Sources of SELECT Queries](#data-sources-of-select-queries)
- [Retrieving Single and Multiple Rows](#retrieving-single-and-multiple-rows)
- [Miscellaneous Options Regarding the Result](#miscellaneous-options-regarding-the-result)
- [Additional Clauses](#additional-clauses)
@@ -35,6 +36,7 @@
- [Using UPDATE](#using-update)
- [Using MODIFY](#using-modify)
- [Using DELETE](#using-delete)
+ - [Example: Exploring ABAP SQL Statements Changing Data in Database Tables](#example-exploring-abap-sql-statements-changing-data-in-database-tables)
- [RAP-Specific ABAP SQL Variants](#rap-specific-abap-sql-variants)
- [More Information](#more-information)
- [Executable Example](#executable-example)
@@ -247,10 +249,16 @@ SELECT ds~col1, ds~col2, ds~col3
INTO ...
```
+⬆️ back to top
-Most of the code snippets in this cheat sheet use database tables as the source in `SELECT` statements. Among others, you can also use internal tables or CDS view entities as data source
-Note that an alias name must be specified for the internal table used as data source. Find more information [here](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapselect_itab.htm).
+### Data Sources of SELECT Queries
+- Most of the code snippets in this cheat sheet use database tables as the source in `SELECT` statements.
+- Among others, you can also use internal tables or CDS view entities as data source.
+- Note that the internal table must be specified as host variable prefixed by `@`, and an alias name must be specified.
+- More information and code snippets:
+ - Section [SELECT Queries with Internal Tables as Data Sources](01_Internal_Tables.md#select-queries-with-internal-tables-as-data-sources) in the *Internal Tables* cheat sheet and in the [ABAP Keyword Documentation](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapselect_itab.htm)
+ - The executable example of the [CDS View Entities](15_CDS_View_Entities.md) cheat sheet covers `SELECT` statements with CDS view entities as data sources.
``` abap
SELECT *
@@ -266,6 +274,7 @@ SELECT *
⬆️ back to top
+
### Retrieving Single and Multiple Rows
@@ -1923,14 +1932,11 @@ INTO @DATA(special_functions).
⬆️ back to top
-
-
-
-
-
-
## Changing Data in Database Tables
+> **💡 Note**
+> The following sections include code patterns. To explore various syntax options with an executable example, see section [Example: Exploring ABAP SQL Statements Changing Data in Database Tables](#example-exploring-abap-sql-statements-changing-data-in-database-tables) below.
+
### Using INSERT
- Inserts one or more rows into a database table specified.
@@ -2076,6 +2082,303 @@ DELETE dbtab FROM TABLE @( VALUE #( ( comp1 = ... )
⬆️ back to top
+### Example: Exploring ABAP SQL Statements Changing Data in Database Tables
+
+To try the following example out, create a demo class named `zcl_some_class` and paste the code into it. After activation, choose *F9* in ADT to execute the class. The example uses a database table of the ABAP cheat sheets repository and is set up to display output in the console.
+
+
+```abap
+CLASS zcl_some_class DEFINITION
+ PUBLIC
+ FINAL
+ CREATE PUBLIC .
+
+ PUBLIC SECTION.
+ INTERFACES if_oo_adt_classrun.
+ PROTECTED SECTION.
+ PRIVATE SECTION.
+
+ENDCLASS.
+
+
+
+CLASS zcl_some_class IMPLEMENTATION.
+
+ METHOD if_oo_adt_classrun~main.
+
+ "--------------------------- INSERT ---------------------------
+
+ "Deleting the contents of a demo database table to start with an empty database table
+ DELETE FROM zdemo_abap_tab1.
+
+ "Inserting a single row into a database table
+ DATA(row_a) = VALUE zdemo_abap_tab1( key_field = 1 char1 = 'aaa' char2 = 'bbb' num1 = 10 num2 = 100 ).
+ INSERT zdemo_abap_tab1 FROM @row_a.
+
+ "Alternative syntax, same effect
+ DATA(row_b) = VALUE zdemo_abap_tab1( key_field = 2 char1 = 'ccc' char2 = 'ddd' num1 = 20 num2 = 200 ).
+ INSERT INTO zdemo_abap_tab1 VALUES @row_b.
+
+ "Line is created inline using the VALUE operator as part of a host expression
+ INSERT zdemo_abap_tab1 FROM @( VALUE #( key_field = 3 char1 = 'eee' char2 = 'fff' num1 = 30 num2 = 300 ) ).
+
+ "Inserting multiple lines from an internal table into a database table.
+ "Make sure that the internal table does not contain a line having the same key
+ "as an existing row in the database table. Otherwise, a runtime error occurs.
+ TYPES it_type TYPE TABLE OF zdemo_abap_tab1 WITH EMPTY KEY.
+ DATA(it_a) = VALUE it_type( ( key_field = 4 char1 = 'ggg' char2 = 'hhh' num1 = 40 num2 = 400 )
+ ( key_field = 5 char1 = 'iii' char2 = 'jjj' num1 = 50 num2 = 500 ) ).
+ INSERT zdemo_abap_tab1 FROM TABLE @it_a.
+
+ "Inserting lines from a table declared inline using the VALUE operator
+ "as part of a host expression
+ INSERT zdemo_abap_tab1 FROM TABLE @( VALUE #( ( key_field = 6 char1 = 'kkk' char2 = 'lll' num1 = 60 num2 = 600 )
+ ( key_field = 7 char1 = 'mmm' char2 = 'nnn' num1 = 70 num2 = 700 ) ) ).
+
+ "ACCEPTING DUPLICATE KEYS addition: To avoid the runtime error mentioned above,
+ "all lines that would produce duplicate entries in the database table
+ "regarding the keys are discarded and sy-subrc is set to 4.
+ DATA(it_b) = VALUE it_type( ( key_field = 1 char1 = '###' char2 = '###' num1 = 0 num2 = 0 )
+ ( key_field = 8 char1 = 'ooo' char2 = 'ppp' num1 = 80 num2 = 800 ) ).
+ INSERT zdemo_abap_tab1 FROM TABLE @it_b ACCEPTING DUPLICATE KEYS.
+ ASSERT sy-subrc = 4.
+
+ "Inserting the result set of an embedded subquery
+ "Various options are available. The examples show a selection.
+ "The subqueries use an internal table.
+
+ "No restriction specified, all entries are inserted
+ DATA(it_c) = VALUE it_type( ( key_field = 9 char1 = 'qqq' char2 = 'rrr' num1 = 90 num2 = 900 )
+ ( key_field = 10 char1 = 'sss' char2 = 'ttt' num1 = 100 num2 = 1000 )
+ ( key_field = 11 char1 = 'uuu' char2 = 'vvv' num1 = 110 num2 = 1100 ) ).
+
+ INSERT zdemo_abap_tab1 FROM ( SELECT key_field, char1, char2, num1, num2 FROM @it_c AS itc ).
+
+ "WHERE condition specified
+ DATA(it_d) = VALUE it_type( ( key_field = 12 char1 = 'www' char2 = 'xxx' num1 = 120 num2 = 1200 )
+ ( key_field = 13 char1 = 'yyy' char2 = 'zzz' num1 = 130 num2 = 1300 )
+ ( key_field = 14 char1 = 'AAA' char2 = 'BBB' num1 = 140 num2 = 1400 ) ).
+
+ INSERT zdemo_abap_tab1 FROM ( SELECT key_field, char1, char2, num1, num2 FROM @it_d AS itd WHERE key_field <= 13 ).
+
+ "Using a subquery and replacing existing values in a CASE expression
+ DATA(it_e) = VALUE it_type( ( key_field = 15 char1 = 'X' char2 = 'DDD' num1 = 150 num2 = 1500 )
+ ( key_field = 16 char1 = 'Y' char2 = 'FFF' num1 = 160 num2 = 1600 )
+ ( key_field = 17 char1 = 'Z' char2 = 'HHH' num1 = 170 num2 = 1700 ) ).
+
+ INSERT zdemo_abap_tab1 FROM (
+ SELECT key_field,
+ CASE WHEN char1 = 'X' THEN 'CCC'
+ WHEN char1 = 'Y' THEN 'EEE'
+ ELSE 'GGG'
+ END AS char1,
+ char2, num1, num2
+ FROM @it_e AS ite ).
+
+ "Retrieving all database entries for display purposes
+ SELECT * FROM zdemo_abap_tab1 INTO TABLE @DATA(itab_insert).
+ out->write( data = itab_insert name = `itab_insert` ).
+
+**********************************************************************
+
+ "-------- Exploring constructor expressions for internal tables created in place --------
+ "The examples explore constructor expressions that construct internal tables in place and that can be
+ "specified after the TABLE addition (as a host expressions), apart from an existing data object.
+ "For more information about constructor expressions, see the ABAP Keyword Documentation and the
+ "Constructor Expressions cheat sheet.
+ DELETE FROM zdemo_abap_tab1.
+
+ "VALUE operator as shown above, creating an internal table in place
+ INSERT zdemo_abap_tab1 FROM TABLE @( VALUE #( ( key_field = 1 char1 = 'aaa' char2 = 'bbb' num1 = 10 num2 = 100 )
+ ( key_field = 2 char1 = 'ccc' char2 = 'ddd' num1 = 20 num2 = 200 ) ) ).
+
+ "FOR LOOP with VALUE
+ DATA(it_f) = VALUE it_type( ( key_field = 3 char1 = 'ee' char2 = 'ff' num1 = 30 num2 = 300 )
+ ( key_field = 4 char1 = 'gg' char2 = 'hh' num1 = 40 num2 = 400 )
+ ( key_field = 5 char1 = 'ii' char2 = 'jj' num1 = 50 num2 = 500 ) ).
+
+ "In the example, the internal table from above is looped across. The index value is
+ "stored and used to modify field values of the internal table. In doing so, the modified
+ "internal table values are inserted into the database table.
+ INSERT zdemo_abap_tab1 FROM TABLE @( VALUE #( FOR wa IN it_f INDEX INTO idx ( key_field = wa-key_field
+ char1 = wa-char1 && idx
+ char2 = wa-char2 && idx
+ num1 = wa-num1 + idx
+ num2 = wa-num2 + idx ) ) ).
+
+ "CORRESPONDING
+ TYPES: BEGIN OF s1,
+ key_field TYPE i,
+ char1 TYPE c LENGTH 5,
+ num1 TYPE i,
+ END OF s1,
+ it_type_s1 TYPE TABLE OF s1 WITH EMPTY KEY,
+ BEGIN OF s2,
+ key TYPE i,
+ char TYPE c LENGTH 5,
+ number1 TYPE i,
+ num2 TYPE p LENGTH 8 DECIMALS 2,
+ END OF s2,
+ it_type_s2 TYPE TABLE OF s2 WITH EMPTY KEY.
+
+ "Identical component names in the internal table
+ "The example includes compatible and convertible types.
+ DATA(it_g) = VALUE it_type_s1( ( key_field = 6 char1 = 'kkk' num1 = 60 )
+ ( key_field = 7 char1 = 'lll' num1 = 70 ) ).
+
+ INSERT zdemo_abap_tab1 FROM TABLE @( CORRESPONDING #( it_g ) ).
+
+ "Non-identical component names in the internal table; using the MAPPING/EXCEPT additions
+ "The example includes compatible and convertible types.
+ DATA(it_h) = VALUE it_type_s2( ( key = 8 char = 'mmm' number1 = 80 num2 = '1.23' )
+ ( key = 9 char = 'nnn' number1 = 90 num2 = '4.56' ) ).
+
+ INSERT zdemo_abap_tab1 FROM TABLE @( CORRESPONDING #( it_h MAPPING key_field = key char2 = char num1 = number1 EXCEPT num2 ) ).
+
+ SELECT * FROM zdemo_abap_tab1 INTO TABLE @DATA(itab_constr).
+ out->write( data = itab_constr name = `itab_constr` ).
+
+**********************************************************************
+
+ "--------------------------- UPDATE ---------------------------
+
+ "Preparing a demo database table
+ DELETE FROM zdemo_abap_tab1.
+ INSERT zdemo_abap_tab1 FROM TABLE @( VALUE #( ( key_field = 1 char1 = 'aaa' char2 = 'bbb' num1 = 10 num2 = 100 )
+ ( key_field = 2 char1 = 'ccc' char2 = 'ddd' num1 = 20 num2 = 200 )
+ ( key_field = 3 char1 = 'eee' char2 = 'fff' num1 = 30 num2 = 300 ) ) ).
+
+ "Changing content by overwriting entire rows based on a structure
+ DATA(row_c) = VALUE zdemo_abap_tab1( key_field = 1 char1 = 'ggg' char2 = 'hhh' num1 = 12 num2 = 123 ).
+ UPDATE zdemo_abap_tab1 FROM @row_c.
+
+ "The following example specifies a value for the key field that does not
+ "exist in the database table. Consequently, no update takes place, the sy-subrc
+ "value is set to 4.
+ UPDATE zdemo_abap_tab1 FROM @( VALUE #( key_field = 4 char1 = 'iii' char2 = 'jjj' num1 = 44 num2 = 456 ) ).
+ ASSERT sy-subrc = 4.
+
+ "Changing content by overwriting entire rows based on rows in an internal table
+ DATA(it_j) = VALUE it_type( ( key_field = 2 char1 = 'kkk' char2 = 'lll' num1 = 23 num2 = 234 )
+ ( key_field = 3 char1 = 'mmm' char2 = 'nnn' num1 = 34 num2 = 345 ) ).
+
+ UPDATE zdemo_abap_tab1 FROM TABLE @it_j.
+
+ "Using a host expression, internal table created in place
+ INSERT zdemo_abap_tab1 FROM @( VALUE #( key_field = 4 char1 = 'ooo' char2 = 'ppp' num1 = 40 num2 = 400 ) ).
+ "The following example does not specify two components. Initial values are used.
+ UPDATE zdemo_abap_tab1 FROM TABLE @( VALUE #( ( key_field = 4 char2 = 'qqq' num1 = 44 ) ) ).
+
+ "INDICATORS addition: Changing content of specific fields without overwriting
+ "existing values of other fields
+ TYPES ind_wa TYPE zdemo_abap_tab1 WITH INDICATORS comp_ind TYPE abap_boolean.
+ TYPES ind_tab TYPE TABLE OF ind_wa WITH EMPTY KEY.
+
+ INSERT zdemo_abap_tab1 FROM TABLE @( VALUE #( ( key_field = 5 char1 = 'rrr' char2 = 'sss' num1 = 50 num2 = 500 )
+ ( key_field = 6 char1 = 'ttt' char2 = 'uuu' num1 = 60 num2 = 600 ) ) ).
+
+ UPDATE zdemo_abap_tab1 FROM TABLE @( VALUE ind_tab( ( key_field = 5 char1 = 'vvv' char2 = 'www' num1 = 56 num2 = 567
+ comp_ind-char1 = abap_true comp_ind-char2 = abap_false
+ comp_ind-num1 = abap_true comp_ind-num2 = abap_false )
+ ( key_field = 6 char1 = 'xxx' char2 = 'yyy' num1 = 67 num2 = 678
+ comp_ind-char1 = abap_false comp_ind-char2 = abap_true
+ comp_ind-num1 = abap_false comp_ind-num2 = abap_true ) ) )
+ INDICATORS SET STRUCTURE comp_ind.
+
+ SELECT * FROM zdemo_abap_tab1 INTO TABLE @DATA(itab_update).
+ out->write( data = itab_update name = `itab_update` ).
+
+ "SET addition: Changing values of specific fields in all table rows
+ "Preparing a demo database table
+ DELETE FROM zdemo_abap_tab1.
+ INSERT zdemo_abap_tab1 FROM TABLE @( VALUE #( ( key_field = 1 char1 = 'aaa' char2 = 'bbb' num1 = 10 num2 = 100 )
+ ( key_field = 2 char1 = 'ccc' char2 = 'ddd' num1 = 20 num2 = 200 )
+ ( key_field = 3 char1 = 'eee' char2 = 'fff' num1 = 30 num2 = 300 ) ) ).
+
+ "The following example transforms the character string of a
+ "component to upper case.
+ UPDATE zdemo_abap_tab1 SET char1 = upper( char1 ).
+
+ "Setting a WHERE condition
+ UPDATE zdemo_abap_tab1 SET char2 = concat( char2, '#' ), num1 = num1 + 1, num2 = num2 + 2 WHERE num1 > 15.
+
+ SELECT * FROM zdemo_abap_tab1 INTO TABLE @DATA(itab_update_set).
+ out->write( data = itab_update_set name = `itab_update_set` ).
+
+**********************************************************************
+
+ "--------------------------- 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
+ DELETE FROM zdemo_abap_tab1.
+
+ "Inserting a single row into a database table
+ DATA(row_d) = VALUE zdemo_abap_tab1( key_field = 1 char1 = 'aaa' char2 = 'bbb' num1 = 10 num2 = 100 ).
+ MODIFY zdemo_abap_tab1 FROM @row_d.
+
+ "Inserting a table row using a host expression and a row created in place
+ MODIFY zdemo_abap_tab1 FROM @( VALUE #( key_field = 2 char1 = 'ccc' char2 = 'ddd' num1 = 20 num2 = 200 ) ).
+
+ "Inserting a table row ...
+ MODIFY zdemo_abap_tab1 FROM @( VALUE #( key_field = 3 char1 = 'eee' char2 = 'fff' num1 = 30 num2 = 300 ) ).
+ "... and modifying it. No new row is inserted, the existing one is modified as the key already exists.
+ MODIFY zdemo_abap_tab1 FROM @( VALUE #( key_field = 3 char1 = 'ggg' char2 = 'hhh' num1 = 34 num2 = 345 ) ).
+
+ "Inserting table rows from an internal table
+ MODIFY zdemo_abap_tab1 FROM TABLE @( VALUE #( ( key_field = 4 char1 = 'iii' char2 = 'jjj' num1 = 40 num2 = 400 )
+ ( key_field = 5 char1 = 'kkk' char2 = 'lll' num1 = 50 num2 = 500 ) ) ).
+ "Modifying/inserting from an internal table
+ MODIFY zdemo_abap_tab1 FROM TABLE @( VALUE #( ( key_field = 4 char1 = 'mmm' char2 = 'nnn' num1 = 45 num2 = 456 )
+ ( key_field = 5 char1 = 'ooo' char2 = 'ppp' num1 = 56 num2 = 567 )
+ ( key_field = 6 char1 = 'qqq' char2 = 'rrr' num1 = 60 num2 = 600 )
+ ( key_field = 7 char1 = 'sss' char2 = 'ttt' num1 = 70 num2 = 700 ) ) ).
+
+ SELECT * FROM zdemo_abap_tab1 INTO TABLE @DATA(itab_modify).
+ out->write( data = itab_modify name = `itab_modify` ).
+
+**********************************************************************
+
+ "--------------------------- DELETE ---------------------------
+
+ "Deleting the contents of a demo database table to start with an empty database table
+ DELETE FROM zdemo_abap_tab1.
+ SELECT * FROM zdemo_abap_tab1 INTO TABLE @DATA(itab_delete).
+ ASSERT itab_delete IS INITIAL.
+
+ "Inserting demo data into the database table
+ INSERT zdemo_abap_tab1 FROM TABLE @( VALUE #( ( key_field = 1 num1 = 10 )
+ ( key_field = 2 num1 = 20 )
+ ( key_field = 3 num1 = 30 )
+ ( key_field = 4 num1 = 40 )
+ ( key_field = 5 num1 = 50 )
+ ( key_field = 6 num1 = 60 )
+ ( key_field = 7 num1 = 70 )
+ ( key_field = 8 num1 = 80 ) ) ).
+
+ "Rows are deleted based on a condition
+ DELETE FROM zdemo_abap_tab1 WHERE key_field >= 7.
+
+ "Deleting a single row based on entries in a structure
+ "Keys are specified
+ DELETE zdemo_abap_tab1 FROM @( VALUE #( key_field = 1 ) ).
+
+ "There is no entry with key_field = 0.
+ DELETE zdemo_abap_tab1 FROM @( VALUE zdemo_abap_tab1( num1 = 20 ) ).
+ ASSERT sy-subrc = 4.
+
+ "Deleting multiple rows based on entries in an internal table
+ DELETE zdemo_abap_tab1 FROM TABLE @( VALUE #( ( key_field = 2 )
+ ( key_field = 3 ) ) ).
+
+ SELECT * FROM zdemo_abap_tab1 INTO TABLE @itab_delete.
+ out->write( data = itab_delete name = `itab_delete` ).
+ ENDMETHOD.
+ENDCLASS.
+```
+
+⬆️ back to top
+
### RAP-Specific ABAP SQL Variants
There are [RAP](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenarap_glosry.htm)-specific variants of ABAP SQL statements that use the `MAPPING FROM ENTITY` addition. Find more information [here](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapmapping_from_entity.htm) and in the [ABAP for RAP: Entity Manipulation Language (ABAP EML)](08_EML_ABAP_for_RAP.md#abap-sql-statements-with-bdef-derived-types) cheat sheet.
@@ -2098,7 +2401,7 @@ There are [RAP](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index
- ABAP SQL statements can contain [SQL path expressions](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abensql_path_expression_glosry.htm). For more information, see [here](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenabap_sql_path.htm). The executable example of the CDS view entities cheat sheet includes demo SQL statements.
- Find [here](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenabap_sql_exceptions.htm) and overview on exceptions that can occur in the context of ABAP SQL statements.
- As a rule, bear in mind performance aspects when using ABAP SQL statements. Find more information in the [Performance Notes](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenabap_sql_perfo.htm). The code snippets here only focus on syntax options.
- - You can specify hierarchy data as a data source in ABAP SQL `SELECT` statements. Find more information and examples in the [ABAP Keyword Documentation](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenselect_hierarchy_data.htm).
+ - You can specify hierarchy data as a data source in ABAP SQL `SELECT` statements. Find more information and examples in the [ABAP Keyword Documentation](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenselect_hierarchy_data.htm). For working with hierarchies, see the [ABAP SQL: Working with Hierarchies cheat sheet](10_ABAP_SQL_Hierarchies.md).
## Executable Example
[zcl_demo_abap_sql](./src/zcl_demo_abap_sql.clas.abap)
diff --git a/04_ABAP_Object_Orientation.md b/04_ABAP_Object_Orientation.md
index 7353f25..834a25d 100644
--- a/04_ABAP_Object_Orientation.md
+++ b/04_ABAP_Object_Orientation.md
@@ -2176,7 +2176,7 @@ CLASS global_class DEFINITION CREATE PUBLIC FRIENDS other_global_class ... .
The following example demonstrates granting friendship between a global class and a local class (in the CCIMP include, *Local Types* tab in ADT). In the example, friendship is granted in both ways so that the global class can access private components of the local class, and the local class can access private components of the global class.
For more information, see the following topics:
-- [`LOCAL FRIENDS`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapclass_local_friends.htm),
+- [`LOCAL FRIENDS`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapclass_local_friends.htm)
- [`DEFERRED`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapclass_deferred.htm)
**Global class**
@@ -2196,7 +2196,7 @@ CLASS zcl_some_class DEFINITION
PROTECTED SECTION.
PRIVATE SECTION.
TYPES str TYPE string.
- CLASS-METHODS get_hello RETURNING VALUE(hello) TYPE string.
+ CLASS-METHODS get_hello RETURNING VALUE(hello) TYPE str.
ENDCLASS.
@@ -2215,7 +2215,7 @@ ENDCLASS.
**CCDEF include (*Class-relevant Local Types* tab in ADT)**
- Regarding the includes, see the information in section [Excursion: Class Pool and Include Programs](#excursion-class-pool-and-include-programs)
-- The LOCAL FRIENDS addition makes the local class a friend of the global class. The private components of the global class can then be accessed by the local class.
+- The `LOCAL FRIENDS` addition makes the local class a friend of the global class. The private components of the global class can then be accessed by the local class.
```abap
CLASS local_class DEFINITION DEFERRED.
@@ -2223,9 +2223,9 @@ CLASS zcl_some_class DEFINITION LOCAL FRIENDS local_class.
```
**CCIMP include (*Local Types* tab in ADT)**
-- The FRIENDS addition makes the global class a friend of the local class. The private components of the local class can then be accessed by the global class.
+- The `FRIENDS` addition makes the global class a friend of the local class. The private components of the local class can then be accessed by the global class.
- A type declared in the private section of the global class is used to type an attribute.
-- The method, which is also declared in the private section, includes a method call in the implementation. It is a method delcared in the private section of the global class.
+- The method, which is also declared in the private section, includes a method call in the implementation. It is a method declared in the private section of the global class.
```abap
diff --git a/06_Dynamic_Programming.md b/06_Dynamic_Programming.md
index 54c71fc..2b52ae8 100644
--- a/06_Dynamic_Programming.md
+++ b/06_Dynamic_Programming.md
@@ -27,11 +27,12 @@
- [Dynamic Specifications in Statements for Processing Internal Tables](#dynamic-specifications-in-statements-for-processing-internal-tables)
- [Dynamic ABAP SQL Statements](#dynamic-abap-sql-statements)
- [Dynamic Invoke](#dynamic-invoke)
+ - [Dynamic ABAP EML Statements](#dynamic-abap-eml-statements)
- [Dynamic Formatting Option Specifications in String Templates](#dynamic-formatting-option-specifications-in-string-templates)
- [Validating Input for Dynamic Specifications (CL\_ABAP\_DYN\_PRG)](#validating-input-for-dynamic-specifications-cl_abap_dyn_prg)
- [Runtime Type Services (RTTS)](#runtime-type-services-rtts)
- [Getting Type Information at Runtime](#getting-type-information-at-runtime)
- - [RTTI Method Calls](#rtti-method-calls)
+ - [RTTI: Attribute Access and Method Calls](#rtti-attribute-access-and-method-calls)
- [Example: Exploring the RTTI Type Hierarchy](#example-exploring-the-rtti-type-hierarchy)
- [Excursion: Inline Declaration, CAST Operator, Method Chaining](#excursion-inline-declaration-cast-operator-method-chaining)
- [Absolute Names](#absolute-names)
@@ -241,6 +242,9 @@ LOOP AT itab ASSIGNING FIELD-SYMBOL().
-connid = ...
...
ENDLOOP.
+
+"READ TABLE statements
+READ TABLE itab INDEX 1 ASSIGNING FIELD-SYMBOL(