| Syntax | Notes |
| `... INTO TABLE ...` | An internal table is expected for the result set. It may be declared inline to automatically have a suitable type, which also applies to `... INTO ...`. ```abap SELECT FROM dbtab FIELDS * WHERE ... INTO TABLE @itab. SELECT FROM dbtab FIELDS * WHERE ... INTO TABLE @DATA(itab_inl). ``` |
| `... INTO ...` | Expects a structure when used without `TABLE`. ```abap SELECT SINGLE comp1, comp2, comp3 FROM dbtab WHERE ... INTO @struc. SELECT SINGLE comp1, comp2, comp3 FROM dbtab WHERE ... INTO @DATA(struc_inl). ``` |
| `... INTO CORRESPONDING FIELDS OF [TABLE] ...` | - Only the content of columns for which there are identically named components in the target are assigned. - However, if you want to read data into an existing data object and particular fields are specified in the `SELECT` list or `FIELDS` clause, and if the addition is **not** specified, you might stumble on undesired results. - The target data object must contain enough components and the content of the columns are assigned to the components of the target from left to right in the order specified. The content of surplus components of the target is not changed. - Plus, pay attention to [assignment rules](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenselect_into_conversion.htm). - Basic rule: Without `CORRESPONDING ...`, column names do not play a role but only the position. With `CORRESPONDING ...`, the position of the columns does not play a role but only the name. ```abap SELECT SINGLE comp1, comp2, comp3 FROM dbtab WHERE ... INTO CORRESPONDING FIELDS OF @struc. SELECT FROM dbtab FIELDS comp1, comp2, comp3 WHERE ... INTO CORRESPONDING FIELDS OF TABLE @itab. ``` |
| `... APPENDING [CORRESPONDING FIELDS OF] TABLE ...` | The addition `INTO` initializes the target object. When using the addition `APPENDING`, you can retain existing lines in internal tables. `APPENDING` is also possible with the addition `CORRESPONDING FIELDS OF`. ```abap SELECT * FROM dbtab WHERE ... APPENDING TABLE @itab. "APPENDING is also possible with the addition CORRESPONDING FIELDS OF SELECT * FROM dbtab WHERE ... APPENDING CORRESPONDING FIELDS OF TABLE @diff_itab. ``` |
NEW addition: Specifying an anonymous data object as target object |
- Specifying an [anonymous data object](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenanonymous_data_object_glosry.htm) as target object using the addition [`NEW`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapselect_into_target.htm#!ABAP_ALTERNATIVE_3@3@)
- Only to be used after `INTO` and not `APPENDING`.
``` abap "The examples declares target objects as anonymous data objects inline. SELECT * FROM zdemo_abap_flsch INTO TABLE NEW @DATA(itab_ref). SELECT SINGLE * FROM zdemo_abap_flsch INTO NEW @DATA(wa_ref). ``` |
| `... INTO ( dobj1, dob2, ... ) ...` | Apart from reading into structures and internal tables outlined above, you can also read into individual elementary data objects. Here, the individual elementary data objects as target objects are specified in a comma-separated list (e. g. as existing host variables or declared inline) and put between a pair of parentheses. Note: - The comma-separated list must have the same number of elements as columns in the result set. - The content of the columns in the result set is assigned to the data objects specified in the list from left to right in accordance with the order specified in the `SELECT` list. - Note the [assignment rules](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenselect_into_conversion.htm) also in this context. - More information [here](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapinto_clause.htm#!ABAP_ALTERNATIVE_1@1@). ``` abap "Elementary data objects as target data objects DATA id TYPE zdemo_abap_carr-carrid. DATA name TYPE zdemo_abap_carr-carrname. SELECT SINGLE FROM zdemo_abap_carr FIELDS carrid, carrname WHERE carrid = char`LH` INTO ( @id, @name ). "Inline declarations with DATA/FINAL and the "creation of anonymous data objects with NEW are "possible SELECT SINGLE FROM zdemo_abap_carr FIELDS carrid, carrname, url WHERE carrid = char`LH` INTO ( @id, @DATA(name2), NEW @FINAL(dref) ). ``` |
| Subject | Details/Code Snippet |
| `SINGLE` addition: Retrieving a single row into a structure | ``` abap "SINGLE addition "Here, all fields of a single row a read. Specifying an "asterisk * indicates that all fields are to be read. "Alternatively, you can list all the fields separated by comma. "Note that if the selection covers more than one row, e. g. in case "of a non-unique WHERE clause, one of these rows is included in "the result. SELECT SINGLE FROM dbtab FIELDS * WHERE ... INTO @struc. "Existing structure of dbtab's row type "Retrieving a selected set of fields of a single row SELECT SINGLE FROM dbtab FIELDS comp1, comp2, comp3 WHERE ... INTO @DATA(struc2). "Structure declared inline "Alternative syntax without the FIELDS addition "Here, the CORRESPONDING FIELDS OF addition is used. Only the content of "columns that have identically named components in the target data object "is assigned. SELECT SINGLE comp1, comp2, comp3 "Selected set of fields FROM dbtab WHERE ... INTO CORRESPONDING FIELDS OF @struc. "Existing structure ``` |
| Retrieving multiple rows into an internal table | ``` abap SELECT FROM dbtab FIELDS * "All fields WHERE ... INTO TABLE @itab. "itab has an appropriate row type "Alternative syntax without the FIELDS addition SELECT comp1, comp2, comp3 "Selected set of fields FROM dbtab WHERE ... INTO TABLE @DATA(lv_itab). "Internal table declared inline "Selected set of fields, existing variable "See the note on CORRESPONDING FIELDS OF above SELECT FROM dbtab FIELDS comp1, comp2, comp3 "Selected set of fields WHERE ... INTO CORRESPONDING FIELDS OF TABLE @itab. "The addition INTO initializes the target object. When using the addition APPENDING, "you can retain existing lines in internal tables. SELECT * FROM dbtab WHERE ... APPENDING TABLE @itab. "APPENDING is also possible with the addition CORRESPONDING FIELDS OF SELECT * FROM dbtab WHERE ... APPENDING CORRESPONDING FIELDS OF TABLE @diff_itab. ``` |
SELECT loop: Sequentially retrieving multiple rows |
- A `SELECT` loop can be opened if the assignment is made to a structure and the addition `SINGLE` is not used.
- If the row is found, the system field `sy-subrc` is set to `0`.
- The loop must be closed using `ENDSELECT`.
- To terminate the loop completely, you can use the statement [`EXIT`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapexit_loop.htm).
- Note: As covered further down, when using the addition `PACKAGE SIZE` and storing the result in a table, a loop is opened, too.
``` abap SELECT FROM dbtab FIELDS * WHERE ... INTO @struc. IF sy-subrc = 0. ... "For example, making changes on data and adding the row to an internal table. ENDIF. ENDSELECT. ``` |
| Checking the existence of a row in a database table | ``` abap "The example uses @abap_true. Other specifications are possible, e.g. 'X'. SELECT SINGLE @abap_true FROM dbtab WHERE ... INTO @DATA(exists). IF exists = abap_true. ... ENDIF. ``` |
DISTINCT addition: Removing rows that occur more than once in a multirow result set |
- Cannot be used with the addition `SINGLE`.
- See more information [here](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapselect_clause.htm).
``` abap "The following example assumes that there are multiple flights "from a city of the specified carrier with the particular destination. "Assume there are 5 flights available from Frankfurt (cityfrom) that "matches the WHERE clause. The first statement only returns one entry "in the internal table, the second 5 (all). "Using the DISTINCT addition SELECT DISTINCT cityfrom FROM zdemo_abap_flsch WHERE carrid = 'LH' AND cityto = 'NEW YORK' INTO TABLE @DATA(itab_distinct). "Not using the DISTINCT addition SELECT cityfrom FROM zdemo_abap_flsch WHERE carrid = 'LH' AND cityto = 'NEW YORK' INTO TABLE @DATA(itab_no_distinct). ``` |
UP TO n ROWS addition: Limiting the number of returned table rows |
[`UP TO n ROWS`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapselect_up_to_offset.htm)
``` abap "A maximum of five rows are to be returned "If the INTO clause is the last clause, the UP TO clause must be positioned after it. SELECT * FROM dbtab WHERE ... INTO TABLE @DATA(itab_upto) UP TO 5 ROWS. ``` |
OFFSET n addition: Returning only the table rows after a row with a specified count from the result set |
- [`OFFSET n`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapselect_up_to_offset.htm#!ABAP_ADDITION_2@2@)
- You can only use the addition, if an `ORDER BY` clause is specified.
``` abap "In the example, data of all flights are retrieved, except for the 2 flights "with the shortest flight time. SELECT * FROM ztest_abap_flsch WHERE carrid = 'LH' ORDER BY fltime ASCENDING INTO TABLE @DATA(itab) OFFSET 2. ``` |
PACKAGE SIZE n addition: Storing the result in packages of a specified number of rows |
The addition [`PACKAGE SIZE n`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapinto_clause.htm#!ABAP_ONE_ADD@1@) can be specified after `INTO TABLE` and `APPENDING TABLE`. A `SELECT` loop ist opened. After `PACKAGE SIZE`, the number of rows is specified (which can be a host variable, host expression or a literal of type `i`) denoting the number of rows to be inserted in the target object per iteration.
``` abap SELECT FROM dbtab FIELDS comp1, comp2, comp3 WHERE ... INTO TABLE @DATA(itab_pack) PACKAGE SIZE n. ... ENDSELECT. ``` |
INDICATORS [NOT] NULL STRUCTURE addition: Specifying null indicators |
- The `INDICATORS ...` addition is used to specify indicators such as the [null indicator](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abennull_indicator_glosry.htm) and store information about which columns of the result set contain the null value and which do not.
- In the example, an appropriate target table is defined to also store information about which columns of the result set contain the null value and which do not.
- More syntax options are available for `INDICATORS ...`. Find more information [here](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapselect_indicators.htm).
``` abap "The following example uses a left outer join to intentionally create null values. For "this purpose, two demo database tables of the cheat sheet repository are cleared and "populated with specific values to visualize null values. DELETE FROM zdemo_abap_tab1. DELETE FROM zdemo_abap_tab2. MODIFY zdemo_abap_tab1 FROM TABLE @( VALUE #( ( key_field = 1 char1 = 'a' char2 = 'y' ) ( key_field = 2 char1 = 'b' char2 = 'z' ) ) ). MODIFY zdemo_abap_tab2 FROM TABLE @( VALUE #( ( key_field = 1 char1 = 'a' ) ( key_field = 2 char1 = 'a' ) ( key_field = 3 char1 = 'b' ) ( key_field = 4 ) ) ). "Note that for the entry 'key_field = 4' no char1 value was passed. "char1 is a shared column of the two database tables, and which is used in "the ON condition of the join. Since there is no entry in char1 for 'key_field = 4', "the joined values are null in that case. "The example visualizes the null values. The INDICATORS addition is used to specify "indicators such as the null indicator. In the example, an appropriate target table "is defined to also store information about which columns of the result set contain "the null value and which do not. TYPES: BEGIN OF st4null, BEGIN OF s2, key_field TYPE zdemo_abap_tab2-key_field, char2 TYPE zdemo_abap_tab1-char2, END OF s2, BEGIN OF nulls, key_field TYPE c LENGTH 1, char2 TYPE c LENGTH 1, END OF nulls, END OF st4null. DATA joined_tab_w_null_ind TYPE TABLE OF st4null WITH EMPTY KEY. SELECT tab2~key_field, tab1~char2 FROM zdemo_abap_tab2 AS tab2 LEFT OUTER JOIN zdemo_abap_tab1 AS tab1 ON tab1~char1 = tab2~char1 INTO TABLE @joined_tab_w_null_ind INDICATORS NULL STRUCTURE nulls. *Internal table content: *S2 NULLS *KEY_FIELD CHAR2 KEY_FIELD CHAR2 *1 y *KEY_FIELD CHAR2 KEY_FIELD CHAR2 *2 y *KEY_FIELD CHAR2 KEY_FIELD CHAR2 *3 z *KEY_FIELD CHAR2 KEY_FIELD CHAR2 *4 X ``` |
| Clause | Details/Code Snippet |
GROUP BY |
[`GROUP BY`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapgroupby_clause.htm)
clause: Combining groups of table rows in the result set. You
can also use [SQL expressions](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abensql_expression_glosry.htm "Glossary Entry")
here. Multiple clause elements are separated by a comma. Find more information and syntax options in the [ABAP Keyword Documentation](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapgroupby_clause.htm).
Note that the `GROUP BY` clause requires all columns that are
directly specified in the `SELECT` list or specified there as an
argument of an SQL expression to be specified. An exception to this is
[aggregate
functions](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenaggregate_function_glosry.htm "Glossary Entry")
in [aggregate
expressions](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenaggregate_expression_glosry.htm "Glossary Entry")
(except [grouping
functions](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abengrouping_glosry.htm "Glossary Entry"))
as shown in the following example.
In the example below, the database table rows that have the same content in column `comp1` are combined. The lowest and highest values in column `comp2` are determined for each of these groups and placed into the combined row.
``` abap SELECT FROM dbtab FIELDS comp1, MIN( comp2 ) AS min, MAX( comp2 ) AS max WHERE ... GROUP BY comp1 INTO ... ``` |
HAVING |
[`HAVING`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abaphaving_clause.htm)
clause: Limiting the number of table rows in groups in the
result by setting conditions on these rows. The rows for which a
logical expression is true are inserted in the target variable. Note
that `HAVING` can only be used together with `GROUP BY`.
``` abap SELECT FROM dbtab FIELDS comp1, MIN( comp2 ) AS min, MAX( comp3 ) AS max WHERE ... GROUP BY comp1 HAVING comp1 LIKE '%XYZ%' AND SUM( comp4 ) > 100 INTO ... ``` |
ORDER BY |
[`ORDER BY`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abaporderby_clause.htm)
clause: Sorting the result set by specified columns.
The following example shows the ordering of the result set based on the
content of the primary key of the [data source](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abendata_source_glosry.htm "Glossary Entry").
You can also order by any columns and by explicitly specifying the sort order. There are more ordering options, for example, by using SQL expressions. Find more information [here](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abaporderby_clause.htm).
> **💡 Note** >- Not specifying `ORDER BY` means that the order of entries in the result set is undefined. >- If `ORDER BY` and `GROUP BY` clauses are used, all columns specified after `ORDER BY` must also be specified after `GROUP BY`. >- If aggregate functions are specified after `SELECT`, all columns that are specified after `ORDER BY` and that do not have an alias name for an aggregate function must also be specified after `SELECT` and after the `GROUP BY` clause which is required in this case, too. ``` abap SELECT FROM dbtab FIELDS comp1, comp2, comp3 WHERE ... ORDER BY PRIMARY KEY "comp2 ASCENDING "comp2 DESCENDING INTO ... ``` |
WHERE |
[`WHERE`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapwhere.htm) clause: Restricts the number of rows that are included in the result set using logical expressions. See further information on them in the following sections.
``` abap SELECT FROM dbtab FIELDS comp1, comp2, comp3 WHERE comp1 = 'abc' AND comp2 < 123 INTO ... ``` |
| Subject | Details/Code Snippet |
| Using an inner join |
[Inner join](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abeninner_join_glosry.htm):
- Columns of two or more data sources in a result set can be joined.
- Result set:
- Columns of the rows in the result set of the left side with the columns of the rows in the result set of the right side are joined into a single result set.
- Contains all combinations of rows for whose columns the join condition is true.
- If there are identical column names in multiple data sources, use the [column
selector](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abentable_comp_selector_glosry.htm "Glossary Entry")
`~`.
``` abap SELECT a~comp1, a~comp2, b~comp3, c~comp4 FROM dbtab1 AS a INNER JOIN dbtab2 AS b ON a~comp1 = b~comp1 AND a~comp2 = b~comp2 INNER JOIN dbtab3 AS c ON a~comp1 = c~comp1 WHERE ... INTO ... ``` |
| Using an outer join |
[Outer join](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenouter_join_glosry.htm):
- Realized by either a [left outer join](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenleft_outer_join_glosry.htm) or
a [right outer join](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenright_outer_join_glosry.htm).
- Result set:
- Same result set as the inner join.
- Difference: For each selected row on the left side as `LEFT OUTER JOIN` or on the right side as `RIGHT OUTER JOIN`, at least one row is created in the result set even if no rows on the other side meet the condition. The columns on the other side that do not meet the condition are filled with [null values](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abennull_value_glosry.htm).
``` abap "Example for a left outer join SELECT a~comp1, a~comp2, b~comp3, FROM dbtab1 AS a LEFT OUTER JOIN dbtab2 AS b ON a~comp1 = b~comp1 WHERE ... INTO ... ``` |
| Merging the result sets of multiple queries into a single result set |
... using the [set operator](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abencds_set_operators_glosry.htm) [`UNION`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapunion.htm#!ABAP_VARIANT_1@1@). In this case, the rows of the result set of the query after `UNION` are inserted into the result set of the query in front of `UNION`.
``` abap SELECT FROM dbtab1 FIELDS ... WHERE ... UNION SELECT FROM dbtab2 FIELDS ... WHERE ... INTO ... ``` |
| Returning distinct rows of a result set (1) |
... of a query specified before the `INTERSECT` addition that are also available in the result set of the query after the `INTERSECT` addition.
``` abap "If you have imported the cheat sheet repository and already run an example class to fill "the demo tables, you can check the contents of the result sets. SELECT zdemo_abap_flsch~carrid, zdemo_abap_carr~carrname FROM zdemo_abap_flsch INNER JOIN zdemo_abap_carr ON zdemo_abap_carr~carrid = zdemo_abap_flsch~carrid ORDER BY zdemo_abap_flsch~carrid INTO TABLE @DATA(itab_no_intersect). "Using INTERSECT; the result set contains distinct rows SELECT zdemo_abap_flsch~carrid, zdemo_abap_carr~carrname FROM zdemo_abap_flsch INNER JOIN zdemo_abap_carr ON zdemo_abap_carr~carrid = zdemo_abap_flsch~carrid INTERSECT SELECT carrid, carrname FROM zdemo_abap_carr ORDER BY carrid INTO TABLE @DATA(itab_w_intersect). ``` |
| Returning distinct rows of a result set (2) |
... of a query specified before the `EXCEPT` addition that are not available in the result set of the query after the `EXCEPT` addition.
```abap "If you have imported the cheat sheet repository and already run an example class to fill "the demo tables, you can check the contents of the result sets. "Selecting all carrier IDs from a database table that do not exist in an "internal table TYPES: ty_demo_tab TYPE TABLE OF zdemo_abap_flsch WITH EMPTY KEY. DATA(itab) = VALUE ty_demo_tab( ( carrid = 'LH' ) ( carrid = 'LH' ) ( carrid = 'LH' ) ( carrid = 'AA' ) ( carrid = 'AA' ) ). "Selecting all carrier IDs for comparison SELECT carrid FROM zdemo_abap_carr INTO TABLE @DATA(all_carrids). "Using EXCEPT; the result set excludes those carrier IDs present in the "internal table SELECT carrid FROM zdemo_abap_carr EXCEPT SELECT it~carrid FROM @itab AS it INNER JOIN zdemo_abap_carr ON zdemo_abap_carr~carrid = it~carrid ORDER BY carrid ASCENDING INTO TABLE @DATA(itab_w_except). ``` |
char\`abc\`) with [built-in ABAP Dictionary
types](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenddic_builtin_types.htm)
or untyped. See the [Typed Literals](#typed-literals) section further down.
- Regarding host expressions: Structures and internal tables are
possible as host expressions for statements modifying the
content of database tables as shown further down.
- Find more information
[here](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abensql_operands.htm).
> **💡 Note**| Function | Notes | Code Snippet |
| `bintohex( ... )` | Converts byte strings (type `raw`; mapped to ABAP type `x`) to character strings (type `char`) |
The code snippet implements the following:
- To have a self-contained example, a demo internal table with elementary line type (byte-like type `x length 10`) is created.
- The table is filled with demo data.
- An ABAP SQL `SELECT` statement that includes the `bintohex` function retrieves data from the internal table. Note that a warning would be displayed that the `SELECT` command is executed on the database. The warning is suppressed with a pragma.
- [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) (find more information in the Dynamic Programming cheat sheet) is used to demonstrate that the type of the `tline` (the alias name for `table_line`) is character-like.
``` abap TYPES x10 TYPE x LENGTH 10. TYPES ty_raw_tab TYPE TABLE OF x10 WITH EMPTY KEY. DATA(raw_tab) = VALUE ty_raw_tab( ( CONV x10( '68656C6C6F' ) ) ( CONV x10( '776F726C64' ) ) ( CONV x10( '41424150' ) ) ). SELECT bintohex( table_line ) AS tline FROM @raw_tab AS tab INTO TABLE @DATA(conv_to_blob_tab) ##ITAB_DB_SELECT. DATA(tdo_itab) = CAST cl_abap_tabledescr( cl_abap_typedescr=>describe_by_data( conv_to_blob_tab ) ). DATA(table_components_itab) = CAST cl_abap_structdescr( tdo_itab->get_table_line_type( ) )->components. DATA(text_line_type_kind) = table_components_itab[ name = 'TLINE' ]-type_kind. ASSERT text_line_type_kind = cl_abap_typedescr=>typekind_char. ``` |
| `hextobin( ... )` | Converts character strings (type `char` or `numc`) to byte strings (type `raw`; mapped to ABAP type `x`) |
The code snippet implements the following:
- To have a self-contained example, a demo internal table with elementary line type (character-like type `c length 10`) is created.
- The table is filled with demo data.
- An ABAP SQL `SELECT` statement that includes the `hextobin` function retrieves data from the internal table. Note that a warning would be displayed that the `SELECT` command is executed on the database. The warning is suppressed with a pragma.
- RTTI is used to demonstrate that the type of the `tline` (the alias name for `table_line`) is `x`.
``` abap TYPES c10 TYPE c LENGTH 10. TYPES ty_c_tab TYPE TABLE OF c10 WITH EMPTY KEY. DATA(c_tab) = VALUE ty_c_tab( ( '68656C6C6F' ) ( '776F726C64' ) ( '41424150' ) ). SELECT hextobin( table_line ) AS tline FROM @c_tab AS tab INTO TABLE @DATA(hextobin_tab) ##ITAB_DB_SELECT. DATA(tdo_itab) = CAST cl_abap_tabledescr( cl_abap_typedescr=>describe_by_data( hextobin_tab ) ). DATA(table_components_itab) = CAST cl_abap_structdescr( tdo_itab->get_table_line_type( ) )->components. DATA(text_line_type_kind) = table_components_itab[ name = 'TLINE' ]-type_kind. ASSERT text_line_type_kind = cl_abap_typedescr=>typekind_hex. ``` |
| `to_blob( ... )` | Converts from a byte field (type `raw`; mapped to ABAP type `x`) to a byte string (a blob, Binary Large Object; type `rawstring`; mapped to ABAP type `xstring`). |
The code snippet implements the following:
- To have a self-contained example, a demo internal table with elementary line type (byte-like type, `x length 10`) is created.
- The table is filled with demo data.
- An ABAP SQL `SELECT` statement that includes the `to_blob` function retrieves data from the internal table. Note that a warning would be displayed that the `SELECT` command is executed on the database. The warning is suppressed with a pragma.
- RTTI is used to demonstrate that the type of the `tline` (the alias name for `table_line`) is `xstring`.
``` abap TYPES x10 TYPE x LENGTH 10. TYPES ty_raw_tab TYPE TABLE OF x10 WITH EMPTY KEY. DATA(raw_tab) = VALUE ty_raw_tab( ( CONV x10( '68656C6C6F' ) ) ( CONV x10( '776F726C64' ) ) ( CONV x10( '41424150' ) ) ). SELECT to_blob( table_line ) AS tline FROM @raw_tab AS tab INTO TABLE @DATA(conv_to_blob_tab) ##ITAB_DB_SELECT. DATA(tdo_itab) = CAST cl_abap_tabledescr( cl_abap_typedescr=>describe_by_data( conv_to_blob_tab ) ). DATA(table_components_itab) = CAST cl_abap_structdescr( tdo_itab->get_table_line_type( ) )->components. DATA(text_line_type_kind) = table_components_itab[ name = 'TLINE' ]-type_kind. ASSERT text_line_type_kind = cl_abap_typedescr=>typekind_xstring. ``` |
| `to_clob( ... )` | - Converts a fixed-length character string (type `char` or `sstring`) to a clob (character large object; type `string`) - The argument specified in the parentheses can be a table column, literal, host variable/constant, or an SQL expression |
The example class, executable with F9 in ADT, implements the following:
- To have a self-contained example, a demo internal table is created. Among others, it includes the `text` component that is of type `c` with length 255.
- The table is filled with lots of data. `text` receives random strings of a random length (1 - 255) to have data to work with.
- An ABAP SQL `SELECT` statement that includes the `to_clob` function retrieves data from the internal table. Note that a warning would be displayed that the `SELECT` command is executed on the database. The warning is suppressed with a pragma.
- The `to_clob` has an SQL expression as argument. In this case, it is an aggregate expression with `STRING_AGG`, which aggregates the value of multiple rows into a single value.
- Using RTTI, it is demonstrated that the type of the `text_line` component (the alias name for `text`) is `string`. It is then evaluated how many characters the random strings contain. The example is set up to show that the aggregated string exceeds 1333 characters, which is the maximum length of fields of type `sstring`.
```abap CLASS zcl_demo_abap DEFINITION PUBLIC FINAL CREATE PUBLIC . PUBLIC SECTION. INTERFACES if_oo_adt_classrun. METHODS get_random_string IMPORTING VALUE(length) TYPE i OPTIONAL RETURNING VALUE(str) TYPE string. TYPES: BEGIN OF demo_struct, num TYPE i, uuid TYPE sysuuid_x16, text TYPE c LENGTH 255, END OF demo_struct. TYPES ty_demo_tab TYPE SORTED TABLE OF demo_struct WITH UNIQUE KEY num uuid. METHODS get_random_table_content IMPORTING VALUE(table_entry_count) TYPE i OPTIONAL RETURNING VALUE(demo_tab) TYPE ty_demo_tab. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS zcl_demo_abap IMPLEMENTATION. METHOD if_oo_adt_classrun~main. DATA(random_table) = get_random_table_content( 500 ). SELECT num, to_clob( STRING_AGG( text, ',' ) ) AS text_line FROM @random_table AS tab GROUP BY num ORDER BY num INTO TABLE @DATA(aggregated_data) ##ITAB_DB_SELECT. "Checking the type of the text_line component using RTTI DATA(tdo_itab) = CAST cl_abap_tabledescr( cl_abap_typedescr=>describe_by_data( aggregated_data ) ). DATA(table_components_itab) = CAST cl_abap_structdescr( tdo_itab->get_table_line_type( ) )->components. DATA(text_line_type_kind) = table_components_itab[ name = 'TEXT_LINE' ]-type_kind. IF text_line_type_kind = cl_abap_typedescr=>typekind_string. out->write( `The text_line component is of type string.` ). out->write( |\n| ). ENDIF. DATA(lines_w_more_than_1333) = REDUCE i( INIT int = 0 FOR line IN aggregated_data NEXT int = COND #( WHEN strlen( line-text_line ) > 1333 THEN int + 1 ELSE int ) ). out->write( |{ lines_w_more_than_1333 } out of { lines( aggregated_data ) } lines of the internal table have a text_line value exceeding 1333 characters.| ). out->write( |\n| ). ENDMETHOD. METHOD get_random_string. IF length IS NOT SUPPLIED OR length > 255. length = cl_abap_random_int=>create( seed = cl_abap_random=>seed( ) min = 1 max = 255 )->get_next( ). ENDIF. DATA(characters) = `aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ1234567890`. DATA(off) = strlen( characters ) - 1. DO length TIMES. DATA(random_offset) = cl_abap_random_int=>create( seed = cl_abap_random=>seed( ) min = 0 max = off )->get_next( ). TRY. str &&= characters+random_offset(1). CATCH cx_sy_range_out_of_bounds. ENDTRY. ENDDO. ENDMETHOD. METHOD get_random_table_content. IF table_entry_count IS NOT SUPPLIED OR table_entry_count > 1000. table_entry_count = cl_abap_random_int=>create( seed = cl_abap_random=>seed( ) min = 1 max = 1000 )->get_next( ). ENDIF. "Example implementation: For the string aggregation in the SELECT statement, "multiple lines should be created with the same key value in 'num'. DATA(value4num) = 1. DO table_entry_count TIMES. IF sy-index MOD 25 = 0. value4num += 1. ENDIF. INSERT VALUE #( num = value4num uuid = xco_cp=>uuid( )->value text = get_random_string( ) ) INTO TABLE demo_tab. ENDDO. ENDMETHOD. ENDCLASS. ``` |
| `unit_conversion( ... )` | Converts units for a value passed to the `quantity` parameter |
The code snippet implements the following:
- To have a self-contained example, a demo internal table with elementary line type (packed number, `p length 16 decimals 14`) is created.
- The table is filled with demo data.
- Two ABAP SQL `SELECT` statements are included that specify the `unit_conversion` function. Data is retrieved from the internal table and converted. Note that a warning would be displayed that the `SELECT` command is executed on the database. The warning is suppressed with a pragma.
- The example covers the conversion of miles to kilometers and vice versa.
```abap TYPES p_len16dec14 TYPE p LENGTH 16 DECIMALS 14. TYPES ty_plen16dec14_tab TYPE TABLE OF p_len16dec14 WITH EMPTY KEY. DATA(p_tab) = VALUE ty_plen16dec14_tab( ( CONV p_len16dec14( '1' ) ) ( CONV p_len16dec14( '5.7' ) ) ( CONV p_len16dec14( '4.2' ) ) ( CONV p_len16dec14( '25.78' ) ) ). SELECT unit_conversion( quantity = table_line, source_unit = unit`MI`, target_unit = unit`KM` ) AS miles_to_km FROM @p_tab AS tab INTO TABLE @DATA(unit_conv_mi2km_tab) ##ITAB_DB_SELECT. SELECT unit_conversion( quantity = miles_to_km, source_unit = unit`KM`, target_unit = unit`MI` ) AS km_to_miles FROM @unit_conv_mi2km_tab AS tab INTO TABLE @DATA(unit_conv_km2mi_tab) ##ITAB_DB_SELECT. ``` |
| `currency_conversion( ... )` | - Converts currencies for a value passed to the `amount` parameter - Multiple optional parameters can be specified (excluding `client` in ABAP for Cloud Development) |
The code snippet implements the following:
- To have a self-contained example, a demo internal table with elementary line type (packed number, `p length 16 decimals 2`) is created.
- The table is filled with demo data.
- An ABAP SQL `SELECT` statement that includes the `currency_conversion` function retrieves data from the internal table and converts currency values from Euro to US dollars. Note that a warning would be displayed that the `SELECT` command is executed on the database. The warning is suppressed with a pragma.
```abap TYPES p_len16dec2 TYPE p LENGTH 16 DECIMALS 2. TYPES ty_plen16dec2_tab TYPE TABLE OF p_len16dec2 WITH EMPTY KEY. DATA(p_tab) = VALUE ty_plen16dec2_tab( ( CONV p_len16dec2( '1' ) ) ( CONV p_len16dec2( '5.7' ) ) ( CONV p_len16dec2( '4.2' ) ) ( CONV p_len16dec2( '25.78' ) ) ). SELECT currency_conversion( amount = table_line, source_currency = char`EUR`, target_currency = char`USD`, exchange_rate_date = @( cl_abap_context_info=>get_system_date( ) ) ) AS eur2usd FROM @p_tab AS tab INTO TABLE @DATA(curr_unit_conv_eur2usd) ##ITAB_DB_SELECT. ``` |
| `as_geo_json( ... )` | Converts geometry input in the [Extended Well-Known Binary (EWKB) representation](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/ABENDDIC_GEO_DATA.html) to a geometry object in JSON format | ```abap SELECT as_geo_json( some_geo_field ) FROM ... WHERE ... INTO ... ``` |
| ABAP repository object | Notes/Code |
| Table entity | ```abap @ClientHandling.type: #CLIENT_INDEPENDENT @AbapCatalog.deliveryClass: #APPLICATION_DATA @AccessControl.authorizationCheck: #NOT_REQUIRED @EndUserText.label: 'CDS table entity' define table entity zdemo_abap_animals_te { key id : abap.int4; animal_name : abap.char(20); species : abap.char(20); age : abap.int4; country_of_origin : abap.char(20); arrival_date : abap.datn; is_carnivore : abap_boolean; } ``` |
| Writable CDS view entity | ```abap @AccessControl.authorizationCheck: #NOT_REQUIRED @EndUserText.label: 'Writable CDS view entity' @Metadata.ignorePropagatedAnnotations: true define writable view entity zdemo_abap_animals_we as select from zdemo_abap_animals_te { key id, animal_name, species, age, country_of_origin, arrival_date, is_carnivore } ``` |
| Class | ```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. *&---------------------------------------------------------------------* *& Using table entities and writable CDS view entities as data types *& in ABAP *&---------------------------------------------------------------------* DATA struc_table_entity TYPE zdemo_abap_animals_te. TYPES struc_type_table_entity TYPE zdemo_abap_animals_te. DATA(another_struc_table_ent) = VALUE zdemo_abap_animals_te( id = 1 animal_name = 'Zeus' ). DATA struc_writable_ve TYPE zdemo_abap_animals_we. TYPES struc_type_writable_ve TYPE zdemo_abap_animals_we. DATA(another_struc_writable_ve) = VALUE zdemo_abap_animals_we( id = 2 animal_name = 'Leo' ). *&---------------------------------------------------------------------* *& Performing CRUD operations using a table entity and ABAP SQL *&---------------------------------------------------------------------* out->write( `---- Performing CRUD operations on table entities using ABAP SQL ----` ). out->write( |\n| ). DELETE FROM zdemo_abap_animals_te. "DATA animals_table type table of zdemo_abap_animals_te with empty key. INSERT zdemo_abap_animals_te FROM TABLE @( VALUE #( ( id = 1 animal_name = 'Zeus' species = 'Lion' age = 5 country_of_origin = '' arrival_date = '20220115' is_carnivore = abap_true ) ( id = 2 animal_name = 'Leo' species = 'Lion' age = 7 country_of_origin = '' arrival_date = '20241205' is_carnivore = abap_true ) ( id = 3 animal_name = 'Jumbo' species = 'Elephant' age = 10 country_of_origin = 'India' arrival_date = '20190526' is_carnivore = abap_false ) ( id = 4 animal_name = 'Little' species = 'Elephant' age = 4 country_of_origin = 'India' arrival_date = '20240314' is_carnivore = abap_false ) ( id = 5 animal_name = 'Daisy' species = 'Zebra' age = 4 country_of_origin = 'South Africa' arrival_date = '20220207' is_carnivore = abap_false ) ( id = 6 animal_name = 'Buddy' species = 'Owl' age = 3 country_of_origin = 'Canada' arrival_date = '20210111' is_carnivore = abap_true ) ( id = 7 animal_name = 'Sunny' species = 'Dolphin' age = 7 country_of_origin = 'Australia' arrival_date = '20190527' is_carnivore = abap_false ) ( id = 8 animal_name = 'Nala' species = 'Giraffe' age = 6 country_of_origin = 'Tanzania' arrival_date = '20210807' is_carnivore = abap_false ) ( id = 9 animal_name = 'Oscar' species = 'Tiger' age = 8 country_of_origin = 'Russia' arrival_date = '20191018' is_carnivore = abap_true ) ( id = 10 animal_name = 'Charlie' species = 'Chimpanzee' is_carnivore = abap_false ) ( id = 12 ) ) ). out->write( |sy-dbcnt after 1st INSERT: { sy-dbcnt }| ). SELECT COUNT(*) FROM zdemo_abap_animals_te INTO @DATA(number_of_entries). out->write( |Number of data entries after 1st INSERT: { number_of_entries }| ). INSERT zdemo_abap_animals_te FROM TABLE @( VALUE #( ( id = 1 animal_name = 'Lora' species = 'Parrot' age = 2 country_of_origin = 'Mexico' arrival_date = '20240712' is_carnivore = abap_false ) ( id = 11 animal_name = 'Teddy' species = 'Koala' age = 4 country_of_origin = 'Australia' arrival_date = '20240225' is_carnivore = abap_false ) ) ) ACCEPTING DUPLICATE KEYS. out->write( |sy-dbcnt after 2nd INSERT: { sy-dbcnt }| ). SELECT COUNT(*) FROM zdemo_abap_animals_te INTO @number_of_entries. out->write( |Number of data entries after 1st INSERT: { number_of_entries }| ). MODIFY zdemo_abap_animals_te FROM TABLE @( VALUE #( ( id = 12 animal_name = 'Peanut' species = 'Penguin' age = 6 country_of_origin = 'Antarctica' arrival_date = '20200410' is_carnivore = abap_false ) ( id = 13 animal_name = 'Lora' species = 'Parrot' age = 2 country_of_origin = 'Mexico' arrival_date = '20240712' is_carnivore = abap_false ) ( id = 14 animal_name = 'Jumpy' species = 'Kangaroo' age = 4 country_of_origin = 'Australia' arrival_date = '20211117' is_carnivore = abap_false ) ) ). out->write( |sy-dbcnt after MODIFY: { sy-dbcnt }| ). SELECT COUNT(*) FROM zdemo_abap_animals_te INTO @number_of_entries. out->write( |Number of data entries after MODIFY: { number_of_entries }| ). SELECT SINGLE * FROM zdemo_abap_animals_te WHERE id = 10 INTO @DATA(data_set). UPDATE zdemo_abap_animals_te FROM @( VALUE #( BASE data_set age = 3 country_of_origin = 'Uganda' arrival_date = '20231214' ) ). out->write( |sy-dbcnt after 1st UPDATE: { sy-dbcnt }| ). UPDATE zdemo_abap_animals_te SET country_of_origin = 'Kenya' WHERE country_of_origin IS INITIAL. out->write( |sy-dbcnt after 2nd UPDATE: { sy-dbcnt }| ). SELECT * FROM zdemo_abap_animals_te ORDER BY id INTO TABLE @DATA(itab_te). out->write( `Table entries retrieved from table entity:` ). out->write( itab_te ). DELETE FROM zdemo_abap_animals_te WHERE id > 10. out->write( |sy-dbcnt after DELETE: { sy-dbcnt }| ). SELECT COUNT(*) FROM zdemo_abap_animals_te INTO @number_of_entries. out->write( |Number of data entries after DELETE: { number_of_entries }| ). out->write( |\n| ). out->write( repeat( val = '_' occ = 100 ) ). out->write( |\n| ). *&---------------------------------------------------------------------* *& Performing CRUD operations using a writable CDS view entity and ABAP SQL *&---------------------------------------------------------------------* out->write( `---- Performing CRUD operations on a writable CDS view entity using ABAP SQL ----` ). out->write( |\n| ). SELECT COUNT(*) FROM zdemo_abap_animals_we INTO @DATA(we_number_of_entries). out->write( |Number of data entries accessed via writable CDS view entity: { we_number_of_entries }| ). INSERT zdemo_abap_animals_we FROM TABLE @( VALUE #( ( id = 15 ) ( id = 16 animal_name = 'Fuzz' species = 'Polar bear' ) ) ). out->write( |sy-dbcnt after INSERT: { sy-dbcnt }| ). SELECT COUNT(*) FROM zdemo_abap_animals_we INTO @we_number_of_entries. out->write( |Number of data entries after INSERT: { we_number_of_entries }| ). MODIFY zdemo_abap_animals_we FROM @( VALUE #( id = 15 animal_name = 'Hunter' species = 'Jaguar' age = 3 country_of_origin = 'Brazil' arrival_date = '20230423' is_carnivore = abap_true ) ). out->write( |sy-dbcnt after MODIFY: { sy-dbcnt }| ). SELECT SINGLE * FROM zdemo_abap_animals_we WHERE id = 16 INTO @DATA(entry). UPDATE zdemo_abap_animals_we FROM @( VALUE #( BASE entry animal_name = 'Fuzzy' age = 7 country_of_origin = 'Canada' arrival_date = '20190223' is_carnivore = abap_true ) ). out->write( |sy-dbcnt after UPDATE: { sy-dbcnt }| ). DELETE zdemo_abap_animals_we FROM @( VALUE #( id = 10 ) ). out->write( |sy-dbcnt after 1st DELETE: { sy-dbcnt }| ). SELECT COUNT(*) FROM zdemo_abap_animals_we INTO @we_number_of_entries. out->write( |Number of data entries after 1st DELETE: { we_number_of_entries }| ). DELETE FROM zdemo_abap_animals_we WHERE id <= 5. out->write( |sy-dbcnt after 2nd DELETE: { sy-dbcnt }| ). SELECT COUNT(*) FROM zdemo_abap_animals_we INTO @we_number_of_entries. out->write( |Number of data entries after 2nd DELETE: { we_number_of_entries }| ). SELECT * FROM zdemo_abap_animals_we ORDER BY id INTO TABLE @DATA(itab_we). out->write( `Table entries retrieved via writable CDS view entity:` ). out->write( itab_we ). ENDMETHOD. ENDCLASS. ``` |