Update
This commit is contained in:
@@ -1,43 +1,11 @@
|
||||
***********************************************************************
|
||||
*
|
||||
* ABAP cheat sheet: ABAP SQL
|
||||
*
|
||||
* -------------------------- PURPOSE ----------------------------------
|
||||
* - Example to demonstrate various syntax options for working with
|
||||
* persisted data in database tables using ABAP SQL.
|
||||
* - Topics covered: reading from database tables using SELECT, changing
|
||||
* data in database tables using INSERT, UPDATE, MODIFY and DELETE
|
||||
*
|
||||
* ----------------------- GETTING STARTED -----------------------------
|
||||
* - Open the class with the ABAP development tools for Eclipse (ADT).
|
||||
* - Choose F9 to run the class.
|
||||
* - Check the console output.
|
||||
* - To understand the context and the ABAP syntax used, refer to the
|
||||
* notes included in the class as comments or refer to the respective
|
||||
* topic in the ABAP Keyword Documentation.
|
||||
* - Due to the amount of console output, the examples contain numbers
|
||||
* (e.g. 1) ..., 2) ..., 3) ...) for the individual example sections.
|
||||
* Also, the variable name is displayed in most cases. So to find
|
||||
* the relevant output in the console easier and faster, just search
|
||||
* for the number/variable name in the console (CTRL+F in the console)
|
||||
* or use the debugger.
|
||||
*
|
||||
* ----------------------------- NOTE -----------------------------------
|
||||
* The code presented in this class is intended only to support the ABAP
|
||||
* cheat sheets. It is not intended for direct use in a production system
|
||||
* environment. The code examples in the ABAP cheat sheets are primarily
|
||||
* intended to provide a better explanation and visualization of the
|
||||
* syntax and semantics of ABAP statements, not to solve concrete
|
||||
* programming tasks. For production application programs, you should
|
||||
* always work out your own solution for each individual case. There is
|
||||
* no guarantee for the correctness or completeness of the code.
|
||||
* Furthermore, there is no legal responsibility or liability for any
|
||||
* errors or their consequences that may occur when using the the example
|
||||
* code.
|
||||
*
|
||||
***********************************************************************
|
||||
"! <p class="shorttext synchronized">ABAP cheat sheet: ABAP SQL</p>
|
||||
"! Example to demonstrate ABAP SQL.<br>Choose F9 in ADT to run the class.
|
||||
"! <p class="shorttext"><strong>ABAP SQL</strong><br/>ABAP cheat sheet example class</p>
|
||||
"!
|
||||
"! <p>The example class demonstrates syntax and concepts related to ABAP SQL.<br/>
|
||||
"! Choose F9 in ADT to run the class.</p>
|
||||
"!
|
||||
"! <h2>Note</h2>
|
||||
"! <p>Find information on <strong>getting started with the example class</strong> and the
|
||||
"! <strong>disclaimer</strong> in the ABAP Doc comment of class {@link zcl_demo_abap_aux}.</p>
|
||||
CLASS zcl_demo_abap_sql DEFINITION
|
||||
PUBLIC
|
||||
FINAL
|
||||
@@ -72,7 +40,7 @@ CLASS zcl_demo_abap_sql IMPLEMENTATION.
|
||||
|
||||
METHOD if_oo_adt_classrun~main.
|
||||
|
||||
out->write( |ABAP Cheat Sheet Example: ABAP SQL\n\n| ).
|
||||
out->write( |ABAP cheat sheet example: ABAP SQL\n\n| ).
|
||||
out->write( |Using SELECT for multiple purposes\n| ).
|
||||
out->write( |1) Reading a single row from database table into a structure\n\n| ).
|
||||
|
||||
@@ -763,7 +731,7 @@ CLASS zcl_demo_abap_sql IMPLEMENTATION.
|
||||
|
||||
**********************************************************************
|
||||
|
||||
out->write( zcl_demo_abap_aux=>heading( `18) Special functions` ) ).
|
||||
out->write( zcl_demo_abap_aux=>heading( `18a) Special functions` ) ).
|
||||
|
||||
SELECT SINGLE
|
||||
carrid,
|
||||
@@ -820,6 +788,49 @@ CLASS zcl_demo_abap_sql IMPLEMENTATION.
|
||||
out->write( |\n| ).
|
||||
out->write( data = special_functions name = `special_functions` ).
|
||||
|
||||
**********************************************************************
|
||||
|
||||
out->write( zcl_demo_abap_aux=>heading( `18b) coalesce Function` ) ).
|
||||
|
||||
"The null value is a special value that is returned by a database. It indicates an
|
||||
"undefined value or result. Note that, in ABAP, there are no special null values. Do
|
||||
"not confuse the null value with a type-dependent initial value. When using SELECT
|
||||
"statements to read data, null values can be produced by, for example, outer joins.
|
||||
"When the null values are passed to a data object, they are transformed to the
|
||||
"type-dependent initial values. For more information, refer to the ABAP Keyword Documentation.
|
||||
"The following example uses a left outer join to intentionally create null values. For
|
||||
"this purpose, two demo database tables of the ABAP 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 coalesce function is used to replace null values produced by an outer join with
|
||||
"a different value.
|
||||
SELECT tab2~key_field,
|
||||
coalesce( tab1~char1, '-' ) AS coalesced1,
|
||||
coalesce( tab1~char2, '#' ) AS coalesced2,
|
||||
"A coalesce function is a short form of a complex
|
||||
"case distinction such as the following:
|
||||
CASE WHEN tab1~char1 IS NOT NULL THEN tab1~char1
|
||||
ELSE '?'
|
||||
END AS coalesced3
|
||||
|
||||
FROM zdemo_abap_tab2 AS tab2
|
||||
LEFT OUTER JOIN zdemo_abap_tab1 AS tab1 ON tab1~char1 = tab2~char1
|
||||
INTO TABLE @DATA(join_w_null).
|
||||
|
||||
out->write( data = join_w_null name = `join_w_null` ).
|
||||
|
||||
**********************************************************************
|
||||
|
||||
out->write( zcl_demo_abap_aux=>heading( `19) Aggregate Expressions` ) ).
|
||||
@@ -864,64 +875,121 @@ CLASS zcl_demo_abap_sql IMPLEMENTATION.
|
||||
|
||||
**********************************************************************
|
||||
|
||||
out->write( zcl_demo_abap_aux=>heading( `20) More SQL Expressions` ) ).
|
||||
out->write( zcl_demo_abap_aux=>heading( `20a) Arithmetic Expressions` ) ).
|
||||
|
||||
"Arithmetic expressions to perform arithmetic calculations
|
||||
"Cast expressions to convert the value of operands to a dedicated
|
||||
" dictionary type. Note that there are special conversion rules.
|
||||
"String expressions using the operator && to concatenate character
|
||||
" strings.
|
||||
"Case distinctions to carry out either a simple (comparison of the
|
||||
" values of a dedicated operand) or complex (searched case;
|
||||
" evaluation of multiple logical expressions) case distinction.
|
||||
SELECT SINGLE
|
||||
carrid,
|
||||
|
||||
"Arithmethic expressions
|
||||
"operators + - *
|
||||
"Note that / is not allowed in integer expressions as the one below
|
||||
( 1 + 2 ) * 3 AS calc,
|
||||
|
||||
"/ used in an expression using type adjustment in ABAP SQL.
|
||||
"A cast expression converts the value of the operands to the
|
||||
"specified dictionary type. The result is a representation of the
|
||||
"source value in the specified type.
|
||||
CAST( 1 AS D34N ) / CAST( 2 AS D34N ) AS ratio
|
||||
|
||||
FROM zdemo_abap_carr
|
||||
WHERE carrid = 'AA'
|
||||
INTO @DATA(arithmetic_sql_expr).
|
||||
|
||||
out->write( data = arithmetic_sql_expr name = `arithmetic_sql_expr` ).
|
||||
|
||||
**********************************************************************
|
||||
|
||||
out->write( zcl_demo_abap_aux=>heading( `20b) Cast Expressions` ) ).
|
||||
|
||||
SELECT SINGLE
|
||||
carrid,
|
||||
|
||||
"A cast expression converts the value of the operands to the
|
||||
"specified dictionary type. The result is a representation of the
|
||||
"source value in the specified type.
|
||||
CAST( 1 AS D34N ) / CAST( 2 AS D34N ) AS ratio,
|
||||
CAST( connid AS INT4 ) AS connidnum,
|
||||
CAST( @( cl_abap_context_info=>get_system_date( ) ) AS CHAR ) AS dat
|
||||
|
||||
FROM zdemo_abap_fli
|
||||
WHERE carrid = 'AA'
|
||||
INTO @DATA(cast_expr).
|
||||
|
||||
out->write( data = cast_expr name = `cast_expr` ).
|
||||
|
||||
**********************************************************************
|
||||
|
||||
out->write( zcl_demo_abap_aux=>heading( `20c) String Expressions` ) ).
|
||||
|
||||
SELECT SINGLE
|
||||
carrid,
|
||||
|
||||
"String expression using && to concatenate two character strings;
|
||||
"the result of the concatenation must not be longer than
|
||||
"255 characters.
|
||||
carrid && char`_` && carrname AS concat
|
||||
|
||||
FROM zdemo_abap_carr
|
||||
WHERE carrid = 'AA'
|
||||
INTO @DATA(string_expr).
|
||||
|
||||
out->write( data = string_expr name = `string_expr` ).
|
||||
|
||||
**********************************************************************
|
||||
|
||||
out->write( zcl_demo_abap_aux=>heading( `20d) Case Expressions` ) ).
|
||||
|
||||
SELECT SINGLE
|
||||
carrid,
|
||||
|
||||
"Arithmethic expressions
|
||||
"operators + - *
|
||||
"Note that / is not allowed in integer expressions as the
|
||||
"one below.
|
||||
( 1 + 2 ) * 3 AS calc,
|
||||
|
||||
"/ used in an expression using type adjustment in ABAP SQL.
|
||||
"A cast expression converts the value of the operands to the
|
||||
"specified dictionary type. The result is a representation of
|
||||
"the source value in the specified type.
|
||||
CAST( 1 AS D34N ) / CAST( 2 AS D34N ) AS ratio,
|
||||
|
||||
"String expression using && to concatenate two character strings;
|
||||
"the result of the concatenation must not be longer than
|
||||
"255 characters.
|
||||
carrid && carrname AS concat,
|
||||
|
||||
"Case distinction
|
||||
"Simple case distinction
|
||||
"The expression compares the values of an operand with other
|
||||
"operands. Result: The first operand after THEN for which the
|
||||
"comparison is true. If no matches are found, the result
|
||||
"specified after ELSE is selected.
|
||||
"comparison is true. If no matches are found, the result specified
|
||||
"after ELSE is selected.
|
||||
CASE currcode
|
||||
WHEN 'EUR' THEN 'A'
|
||||
WHEN 'USD' THEN 'B'
|
||||
ELSE 'C'
|
||||
WHEN 'EUR' THEN 'A'
|
||||
WHEN 'USD' THEN 'B'
|
||||
ELSE 'C'
|
||||
END AS case_simple,
|
||||
|
||||
"Complex case distinction
|
||||
"The expression evaluates logical expressions. Result: The first
|
||||
"operand after THEN for which the logical expression is true. If
|
||||
"no logical expressions are true, the result specified after ELSE
|
||||
"is selected.
|
||||
"operand after THEN for which the logical expression is true. If no
|
||||
"logical expressions are true, the result specified after ELSE is
|
||||
"selected.
|
||||
CASE WHEN length( carrname ) <= 5 THEN 'small'
|
||||
WHEN length( carrname ) BETWEEN 6 AND 10 THEN 'mid'
|
||||
WHEN length( carrname ) BETWEEN 11 AND 15 THEN 'large'
|
||||
ELSE 'huge'
|
||||
END AS case_complex
|
||||
FROM zdemo_abap_carr
|
||||
WHERE carrid = 'AA'
|
||||
INTO @DATA(more_sql_expr).
|
||||
|
||||
out->write( data = more_sql_expr name = `more_sql_expr` ).
|
||||
FROM zdemo_abap_carr
|
||||
WHERE carrid = 'AA'
|
||||
INTO @DATA(case_expr).
|
||||
|
||||
out->write( data = case_expr name = `case_expr` ).
|
||||
|
||||
**********************************************************************
|
||||
|
||||
out->write( zcl_demo_abap_aux=>heading( `20e) Null Expressions` ) ).
|
||||
|
||||
SELECT
|
||||
carrid,
|
||||
carrname,
|
||||
"The type of the null value is determined by the context.
|
||||
"When the null value is passed to the internal table,
|
||||
"it is converted to the initial value. In the first case,
|
||||
"it is ' '. In the second case, it is 0..
|
||||
CASE WHEN length( carrname ) > 12 THEN char`X`
|
||||
ELSE NULL
|
||||
END AS long_name,
|
||||
CAST( NULL AS INT1 ) AS null_val
|
||||
|
||||
FROM zdemo_abap_carr
|
||||
INTO TABLE @DATA(null_expr).
|
||||
|
||||
out->write( data = null_expr name = `null_expr` ).
|
||||
|
||||
**********************************************************************
|
||||
|
||||
@@ -1049,6 +1117,239 @@ CLASS zcl_demo_abap_sql IMPLEMENTATION.
|
||||
|
||||
out->write( data = itab_like_in name = `itab_like_in` ).
|
||||
|
||||
**********************************************************************
|
||||
|
||||
out->write( zcl_demo_abap_aux=>heading( `25b) SQL conditions (4)` ) ).
|
||||
|
||||
"---- SQL conditions demonstrated with the WHERE clause ----
|
||||
"Note:
|
||||
"- For most of the self-contained examples, an internal table is used as the
|
||||
" data source of SELECT statements to work with simple data.
|
||||
"- For some examples that are covered, such as subqueries, demo database tables
|
||||
" from the cheat sheet repository are used in addition.
|
||||
"- Dynamic specifications are also possible. They are not covered here. See
|
||||
" the Dynamic Programming cheat sheet.
|
||||
|
||||
"---- Types and internal table to work with in the examples ----
|
||||
"Note: You cannot use type string columns in WHERE conditions.
|
||||
TYPES: BEGIN OF demo_struc,
|
||||
id TYPE i,
|
||||
name TYPE c LENGTH 15,
|
||||
"name TYPE string,
|
||||
END OF demo_struc.
|
||||
DATA itab_sql_cond TYPE SORTED TABLE OF demo_struc WITH UNIQUE KEY id.
|
||||
"Populating internal table with data to work with in the examples
|
||||
itab_sql_cond = VALUE #( ( id = 1 name = 'bear' )
|
||||
( id = 2 name = 'camel' )
|
||||
( id = 3 name = 'rabbit' )
|
||||
( id = 4 name = 'zebra' )
|
||||
( id = 5 name = 'dog' )
|
||||
( id = 6 name = 'deer' )
|
||||
( id = 7 name = 'squirrel' )
|
||||
( id = 8 name = 'cheetah' )
|
||||
( id = 9 name = 'elephant' )
|
||||
( id = 10 name = 'donkey' )
|
||||
( id = 11 name = 'fish' )
|
||||
( id = 12 name = 'sheep' ) ).
|
||||
|
||||
"---- =, <>, >, >= (as a selection of possible comparison operators) ----
|
||||
SELECT id FROM @itab_sql_cond AS tab WHERE name = 'bear' INTO TABLE @DATA(it).
|
||||
SELECT id FROM @itab_sql_cond AS tab WHERE name <> 'bear' INTO TABLE @it.
|
||||
SELECT id FROM @itab_sql_cond AS tab WHERE id > 10 INTO TABLE @it.
|
||||
SELECT id FROM @itab_sql_cond AS tab WHERE id >= 10 INTO TABLE @it.
|
||||
|
||||
"---- Combining logical expressions using AND, OR and parentheses ----
|
||||
SELECT id FROM @itab_sql_cond AS tab WHERE id = 1 AND name = 'bear' INTO TABLE @it.
|
||||
SELECT id FROM @itab_sql_cond AS tab WHERE name = 'bear' OR name = 'sheep' INTO TABLE @it.
|
||||
|
||||
"In the following example, the resulting table is initial. One of the expressions
|
||||
"in parentheses is false (AND is used between the expressions in parentheses).
|
||||
"In contrast, the example below returns an entry because of using OR.
|
||||
SELECT id FROM @itab_sql_cond AS tab
|
||||
WHERE ( id = 1 AND name = 'bear' )
|
||||
AND ( id = 20 AND name = 'camel' )
|
||||
INTO TABLE @it.
|
||||
|
||||
SELECT id FROM @itab_sql_cond AS tab
|
||||
WHERE ( id = 1 AND name = 'bear' )
|
||||
OR ( id = 20 AND name = 'camel' )
|
||||
INTO TABLE @it.
|
||||
|
||||
"------------------------ [NOT] BETWEEN ------------------------
|
||||
SELECT id FROM @itab_sql_cond AS tab WHERE id BETWEEN 1 AND 4 INTO TABLE @it.
|
||||
"The condition with BETWEEN above corresponds to the following condition.
|
||||
"The example makes use of a condition specified in parentheses to combine multiple
|
||||
"expressions.
|
||||
SELECT id FROM @itab_sql_cond AS tab WHERE ( id >= 1 AND id <= 4 ) INTO TABLE @it.
|
||||
"Negation with NOT
|
||||
SELECT id FROM @itab_sql_cond AS tab WHERE id NOT BETWEEN 1 AND 4 INTO TABLE @it.
|
||||
|
||||
"------------------------ IS [NOT] INITIAL ------------------------
|
||||
SELECT id FROM @itab_sql_cond AS tab WHERE id IS NOT INITIAL INTO TABLE @it.
|
||||
|
||||
SELECT id FROM @itab_sql_cond AS tab WHERE id IS INITIAL INTO TABLE @it.
|
||||
|
||||
"------------------------ [NOT] LIKE ------------------------
|
||||
"For (not) matching a specified pattern
|
||||
"Note: % (any character string), _ (any character).
|
||||
SELECT name FROM @itab_sql_cond AS tab
|
||||
WHERE name LIKE '%ee%'
|
||||
OR name LIKE '_o%'
|
||||
INTO TABLE @DATA(names). "dog,deer,cheetah,donkey,sheep
|
||||
|
||||
SELECT name FROM @itab_sql_cond AS tab
|
||||
WHERE name NOT LIKE '%ee%'
|
||||
INTO TABLE @names.
|
||||
|
||||
"ESCAPE addition for defining a single-character escape character
|
||||
"In the following example, this character is #. It is placed before
|
||||
"the % character in the specification after LIKE. In this case, %
|
||||
"is escaped and does then not stand for any character string in the
|
||||
"evaluation.
|
||||
"Adding a table entry for this syntax example.
|
||||
itab_sql_cond = VALUE #( BASE itab_sql_cond ( id = 13 name = '100%' ) ).
|
||||
"Any character sequence followed by the % character
|
||||
SELECT name FROM @itab_sql_cond AS tab
|
||||
WHERE name LIKE '%#%' ESCAPE '#'
|
||||
INTO TABLE @names.
|
||||
|
||||
"Deleting the entry because it is not relevant for the further examples.
|
||||
DELETE itab_sql_cond INDEX 13.
|
||||
|
||||
"------------------------ [NOT] IN (using a value set) ------------------------
|
||||
"For (not) matching a value in a set of values specified in parentheses.
|
||||
|
||||
"Single operands on the left side of IN
|
||||
SELECT id FROM @itab_sql_cond AS tab
|
||||
WHERE name IN ( 'camel', 'rabbit', 'dog', 'snake' )
|
||||
INTO TABLE @it.
|
||||
|
||||
"Negation NOT IN; note to use host variables/expressions for local/global data objects
|
||||
DATA(animal) = 'sheep'.
|
||||
SELECT id FROM @itab_sql_cond AS tab
|
||||
WHERE name NOT IN ( 'fish', @animal )
|
||||
INTO TABLE @it.
|
||||
|
||||
"Operand list (a parenthesized comma-separated list) on the left side of IN
|
||||
"For (not) matching value tuples from a set of value tuples specified in parentheses on the right side.
|
||||
"In the following example, two values are specified in the operand list on the left. Consequently,
|
||||
"two values with appropriate types must be specified in parentheses on the right.
|
||||
SELECT id FROM @itab_sql_cond AS tab
|
||||
WHERE ( id, name ) IN ( ( 1, 'bear' ), ( 3, 'rabbit' ), ( 8, 'zebra' ), ( 20, 'dog' ) )
|
||||
INTO TABLE @it.
|
||||
|
||||
|
||||
"------------------------ [NOT] IN (using a subquery) ------------------------
|
||||
"[NOT] IN for matching a value contained in the result set of a subquery
|
||||
|
||||
"In the following example, the subquery reads data from a demo database table.
|
||||
"For a representative result, the table is cleared, and then filled with 'suitable'
|
||||
"data sets.
|
||||
DELETE FROM zdemo_abap_tab1.
|
||||
MODIFY zdemo_abap_tab1 FROM TABLE @( VALUE #( ( key_field = 11 num1 = 11 )
|
||||
( key_field = 12 num1 = 12 )
|
||||
( key_field = 13 num1 = 13 )
|
||||
( key_field = 14 num1 = 14 ) ) ).
|
||||
|
||||
SELECT id FROM @itab_sql_cond AS tab
|
||||
WHERE id IN ( SELECT key_field FROM zdemo_abap_tab1 ) INTO TABLE @it.
|
||||
|
||||
"------------------------ [NOT] IN (using a ranges table) ------------------------
|
||||
"[NOT] IN for checking whether the operands on the left side match a ranges condition in a ranges table
|
||||
|
||||
"Declaring a ranges table
|
||||
DATA rangestab TYPE RANGE OF i.
|
||||
"Populating a ranges table using the VALUE operator
|
||||
rangestab = VALUE #( ( sign = 'I' option = 'BT' low = 1 high = 3 )
|
||||
( sign = 'I' option = 'GE' low = 10 ) ).
|
||||
|
||||
SELECT id FROM @itab_sql_cond AS tab WHERE id IN @rangestab INTO TABLE @it.
|
||||
|
||||
|
||||
"You cannot use logical operators such as CP (conforms to pattern) in the WHERE clause.
|
||||
"In a ranges table, they are possible.
|
||||
"Note:
|
||||
"- Regarding CP: * (any character sequence), + (any character), # (escape character)
|
||||
"- An equivalent example above uses the LIKE addition.
|
||||
DATA rt TYPE RANGE OF demo_struc-name.
|
||||
rt = VALUE #( ( sign = 'I' option = 'CP' low = '*ee*' ) "ee in a string
|
||||
( sign = 'I' option = 'CP' low = '+o*' ) ). "o in second position
|
||||
SELECT name FROM @itab_sql_cond AS tab
|
||||
WHERE name IN @rt
|
||||
INTO TABLE @names.
|
||||
|
||||
"------------------------ EXISTS ------------------------
|
||||
"For checking the result set of a subquery.
|
||||
"The following example reads all entries from the internal table if entries having
|
||||
"the same key also exist in the database table.
|
||||
"Note: The SELECT list in the subquery only contains a literal to determine that
|
||||
"the entry exists. Specifying explicit column names is not relevant.
|
||||
SELECT id FROM @itab_sql_cond AS tab WHERE
|
||||
EXISTS ( SELECT @abap_true FROM zdemo_abap_tab1 WHERE key_field = tab~id )
|
||||
INTO TABLE @it.
|
||||
|
||||
"------------------------ IS [NOT] NULL ------------------------
|
||||
"The null value is a special value that is returned by a database. It indicates an
|
||||
"undefined value or result. Note that, in ABAP, there are no special null values. Do
|
||||
"not confuse the null value with a type-dependent initial value. When using SELECT
|
||||
"statements to read data, null values can be produced by, for example, outer joins.
|
||||
"When the null values are passed to a data object, they are transformed to the
|
||||
"type-dependent initial values. For more information, refer to the ABAP Keyword Documentation.
|
||||
"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 WHERE clause uses the addition IS NULL.
|
||||
"Therefore, the result only contains this entry. char2 is assigned the type-initial
|
||||
"value in the result.
|
||||
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
|
||||
WHERE tab1~char1 IS NULL
|
||||
INTO TABLE @DATA(joined_tab).
|
||||
|
||||
"The following example visualizes the null values. The INDICATORS addition of the
|
||||
"INTO clause 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.
|
||||
"For more information on the syntax, refer to the ABAP Keyword Documentation.
|
||||
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.
|
||||
|
||||
"Negation IS NOT NULL
|
||||
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
|
||||
WHERE tab1~char1 IS NOT NULL
|
||||
INTO TABLE @joined_tab.
|
||||
|
||||
out->write( zcl_demo_abap_aux=>no_output ).
|
||||
|
||||
**********************************************************************
|
||||
|
||||
out->write( zcl_demo_abap_aux=>heading( `Further clauses in SELECT statements` ) ).
|
||||
@@ -1261,6 +1562,60 @@ CLASS zcl_demo_abap_sql IMPLEMENTATION.
|
||||
|
||||
out->write( data = itab_union name = `itab_union` ).
|
||||
|
||||
**********************************************************************
|
||||
|
||||
out->write( zcl_demo_abap_aux=>heading( `33b) Returning distinct rows of a result set using INTERSECT` ) ).
|
||||
|
||||
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).
|
||||
|
||||
out->write( data = itab_no_intersect name = `itab_no_intersect` ).
|
||||
out->write( |\n| ).
|
||||
|
||||
"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).
|
||||
|
||||
out->write( data = itab_no_intersect name = `itab_w_intersect` ).
|
||||
|
||||
**********************************************************************
|
||||
|
||||
out->write( zcl_demo_abap_aux=>heading( `33c) Returning distinct rows of a result set using EXCEPT` ) ).
|
||||
|
||||
"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_except) = 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_except AS it
|
||||
INNER JOIN zdemo_abap_carr ON zdemo_abap_carr~carrid = it~carrid
|
||||
ORDER BY carrid ASCENDING
|
||||
INTO TABLE @DATA(itab_w_except).
|
||||
|
||||
out->write( data = itab_w_except name = `itab_w_except` ).
|
||||
|
||||
**********************************************************************
|
||||
|
||||
out->write( zcl_demo_abap_aux=>heading( `34) Common Table Expressions (CTE) (1)` ) ).
|
||||
@@ -1606,6 +1961,226 @@ CLASS zcl_demo_abap_sql IMPLEMENTATION.
|
||||
select_from_dbtab( ).
|
||||
out->write( data = itab_res name = `itab_res` ).
|
||||
|
||||
**********************************************************************
|
||||
|
||||
out->write( zcl_demo_abap_aux=>heading( `47) Exploring ABAP SQL statements using constructor expressions created in place` ) ).
|
||||
|
||||
TYPES it_type TYPE TABLE OF zdemo_abap_tab1 WITH EMPTY KEY.
|
||||
DELETE FROM zdemo_abap_tab1.
|
||||
|
||||
"--- VALUE ---
|
||||
"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 ) ) ).
|
||||
|
||||
"Using a constructor expression with VALUE and BASE in an UPDATE statement
|
||||
"The example assumes selecting an entry from a database, modifying it, and updating it again,
|
||||
"but the non-modified entries shall remain unchanged.
|
||||
INSERT zdemo_abap_tab1 FROM @( VALUE #( key_field = 100 char1 = 'xxx' char2 = 'yyy' num1 = 100 num2 = 101 ) ).
|
||||
|
||||
SELECT SINGLE * FROM zdemo_abap_tab1 WHERE key_field = 100 INTO @DATA(read_line).
|
||||
UPDATE zdemo_abap_tab1 FROM @( VALUE #( BASE read_line char2 = '#' num1 = 1 ) ).
|
||||
|
||||
"--- 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( zcl_demo_abap_aux=>no_output ).
|
||||
|
||||
**********************************************************************
|
||||
|
||||
out->write( zcl_demo_abap_aux=>heading( `48) Evaluating ABAP System Fields after ABAP SQL Statements` ) ).
|
||||
|
||||
"Clearing a demo database table
|
||||
DELETE FROM zdemo_abap_tab1.
|
||||
|
||||
"--------------------- INSERT ---------------------
|
||||
INSERT zdemo_abap_tab1 FROM @( VALUE #( key_field = 1 ) ).
|
||||
|
||||
ASSERT sy-subrc = 0.
|
||||
ASSERT sy-dbcnt = 1.
|
||||
|
||||
INSERT zdemo_abap_tab1 FROM TABLE @( VALUE #( ( key_field = 2 )
|
||||
( key_field = 3 ) ) ).
|
||||
|
||||
ASSERT sy-subrc = 0.
|
||||
ASSERT sy-dbcnt = 2.
|
||||
|
||||
INSERT zdemo_abap_tab1 FROM TABLE @( VALUE #( ( key_field = 2 )
|
||||
( key_field = 3 ) ) ) ACCEPTING DUPLICATE KEYS.
|
||||
|
||||
ASSERT sy-subrc = 4.
|
||||
ASSERT sy-dbcnt = 0.
|
||||
|
||||
INSERT zdemo_abap_tab1 FROM TABLE @( VALUE #( ( key_field = 3 )
|
||||
( key_field = 4 ) ) ) ACCEPTING DUPLICATE KEYS.
|
||||
|
||||
ASSERT sy-subrc = 4.
|
||||
ASSERT sy-dbcnt = 1.
|
||||
|
||||
"--------------------- UPDATE ---------------------
|
||||
UPDATE zdemo_abap_tab1 FROM @( VALUE #( key_field = 1 num1 = 1 ) ).
|
||||
|
||||
ASSERT sy-subrc = 0.
|
||||
ASSERT sy-dbcnt = 1.
|
||||
|
||||
UPDATE zdemo_abap_tab1 FROM @( VALUE #( key_field = 9999 num1 = 9999 ) ).
|
||||
|
||||
ASSERT sy-subrc = 4.
|
||||
ASSERT sy-dbcnt = 0.
|
||||
|
||||
UPDATE zdemo_abap_tab1 FROM TABLE @( VALUE #( ( key_field = 2 num1 = 2 )
|
||||
( key_field = 3 num1 = 3 ) ) ).
|
||||
|
||||
ASSERT sy-subrc = 0.
|
||||
ASSERT sy-dbcnt = 2.
|
||||
|
||||
UPDATE zdemo_abap_tab1 FROM TABLE @( VALUE #( ( key_field = 4 num1 = 4 )
|
||||
( key_field = 1111 num1 = 1111 ) ) ).
|
||||
|
||||
ASSERT sy-subrc = 4.
|
||||
ASSERT sy-dbcnt = 1.
|
||||
|
||||
"--------------------- MODIFY ---------------------
|
||||
MODIFY zdemo_abap_tab1 FROM @( VALUE #( key_field = 1 num1 = 11 ) ).
|
||||
|
||||
ASSERT sy-subrc = 0.
|
||||
ASSERT sy-dbcnt = 1.
|
||||
|
||||
MODIFY zdemo_abap_tab1 FROM TABLE @( VALUE #( ( key_field = 2 num1 = 22 ) "Entry modified
|
||||
( key_field = 5 num1 = 5 ) ) ). "Entry inserted
|
||||
|
||||
ASSERT sy-subrc = 0.
|
||||
ASSERT sy-dbcnt = 2.
|
||||
|
||||
"--------------------- SELECT ---------------------
|
||||
|
||||
SELECT *
|
||||
FROM zdemo_abap_tab1
|
||||
INTO TABLE @DATA(tab).
|
||||
|
||||
ASSERT sy-subrc = 0.
|
||||
ASSERT sy-dbcnt = 5.
|
||||
ASSERT sy-dbcnt = lines( tab ).
|
||||
|
||||
SELECT *
|
||||
FROM zdemo_abap_tab1
|
||||
WHERE key_field <= 3
|
||||
INTO TABLE @DATA(tab2).
|
||||
|
||||
ASSERT sy-subrc = 0.
|
||||
ASSERT sy-dbcnt = 3.
|
||||
|
||||
SELECT *
|
||||
FROM zdemo_abap_tab1
|
||||
WHERE key_field > 10
|
||||
INTO TABLE @DATA(tab3).
|
||||
|
||||
ASSERT sy-subrc = 4.
|
||||
ASSERT sy-dbcnt = 0.
|
||||
|
||||
"--------------------- DELETE ---------------------
|
||||
DELETE zdemo_abap_tab1 FROM @( VALUE #( key_field = 1 ) ).
|
||||
ASSERT sy-subrc = 0.
|
||||
ASSERT sy-dbcnt = 1.
|
||||
|
||||
DELETE zdemo_abap_tab1 FROM TABLE @( VALUE #( ( key_field = 1 ) "Entry not existent
|
||||
( key_field = 2 )
|
||||
( key_field = 3 ) ) ).
|
||||
|
||||
ASSERT sy-subrc = 4.
|
||||
ASSERT sy-dbcnt = 2.
|
||||
|
||||
DELETE FROM zdemo_abap_tab1 WHERE key_field >= 5.
|
||||
ASSERT sy-subrc = 0.
|
||||
ASSERT sy-dbcnt = 1.
|
||||
|
||||
"Only one entry left in the database table
|
||||
DELETE FROM zdemo_abap_tab1.
|
||||
ASSERT sy-subrc = 0.
|
||||
ASSERT sy-dbcnt = 1.
|
||||
|
||||
SELECT *
|
||||
FROM zdemo_abap_tab1
|
||||
INTO TABLE @DATA(tab4).
|
||||
|
||||
ASSERT sy-subrc = 4.
|
||||
ASSERT sy-dbcnt = 0.
|
||||
|
||||
out->write( zcl_demo_abap_aux=>no_output ).
|
||||
|
||||
**********************************************************************
|
||||
|
||||
out->write( zcl_demo_abap_aux=>heading( `49) Typed literals` ) ).
|
||||
|
||||
"Miscellaneous typed literals in an ABAP SQL statement
|
||||
"Note that typed literals can be specified in read
|
||||
"positions where host variables are possible.
|
||||
DATA(tmstamp) = CONV timestamp( '20240808112517' ).
|
||||
DATA(some_string) = `Some string`.
|
||||
SELECT SINGLE
|
||||
FROM zdemo_abap_fli
|
||||
FIELDS
|
||||
carrid,
|
||||
@some_string AS host_var,
|
||||
char`X` AS flag,
|
||||
int8`32984723948723` AS int8,
|
||||
raw`11` AS raw,
|
||||
numc`1234` AS numc,
|
||||
utclong`2024-01-01T10:01:02,2` AS utc,
|
||||
tims`101507` AS tims,
|
||||
curr`173.95` AS curr,
|
||||
"Multiple cast expressions splitting a time stamp into date and time parts
|
||||
CAST( CAST( div( @tmstamp, 1000000 ) AS CHAR ) AS DATS ) AS date,
|
||||
CAST( substring( CAST( @tmstamp AS CHAR ), 9, 6 ) AS TIMS ) AS time,
|
||||
"Untyped literal
|
||||
'ABAP' AS txt
|
||||
WHERE fldate = datn`20240102`
|
||||
INTO @DATA(misc_typed_literals).
|
||||
|
||||
out->write( data = misc_typed_literals name = `misc_typed_literals` ).
|
||||
|
||||
ENDMETHOD.
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user