| Subject | Notes/Code Snippet |
| Populating an existing structure or a structure created inline | ``` abap "Declaring structured data type and structured data object "(also used in the following snippets) TYPES: BEGIN OF struc_type, a TYPE i, b TYPE c LENGTH 3, END OF struc_type. DATA struc TYPE struc_type. "Note: The data type can be retrieved from the context. Then, # can "be specified. struc = VALUE #( a = 1 b = 'aaa' ). "The following syntax is also possible (explicit data type "specification although the type can be determined). struc = VALUE struc_type( a = 2 b = 'bbb' ). "Using such a VALUE constructor expression instead of, for example, "assigning the component values individually using the component "selector (-). struc-a = 3. struc-b = 'ccc'. "Using an inline declaration "In the following example, the type cannot be retrieved from the "context. Therefore, an explicit specification of the type is "required. DATA(struc2) = VALUE struc_type( a = 4 b = 'ddd' ). ``` |
| Populating an existing internal table or an internal table created inline | ``` abap "Note the extra pair of parentheses for an individual table line. DATA itab TYPE TABLE OF struc_type WITH EMPTY KEY. itab = VALUE #( ( a = 5 b = 'eee' ) ( a = 6 b = 'fff' ) ). "Using such a VALUE constructor expression instead of, for example, "APPEND statements (note the BASE addition for retaining existing "table lines further down) APPEND struc TO itab. APPEND INITIAL LINE TO itab. "Inline declaration, explicit table type specification after VALUE TYPES itab_type TYPE TABLE OF struc_type WITH EMPTY KEY. DATA(itab2) = VALUE itab_type( ( a = 7 b = 'ggg' ) ( a = 8 b = 'hhh' ) ). "Internal table with an elementary line type "Unstructured line types work without component names. DATA(itab3) = VALUE string_table( ( `Hello` ) ( `world` ) ). ``` |
| Creating initial values for all types | ``` abap "Type-specific initial value for data objects by leaving the "VALUE constructor expression empty "Structure (the entire structure is initial) struc = VALUE #( ). "Internal table DATA(itab4) = VALUE itab_type( ). "This basically corresponds to the following data object declarations "DATA itab5 TYPE itab_type. "DATA itab6 TYPE itab_type VALUE IS INITIAL. "Not specifying individual components means these components "remain initial "Component b not specified, i.e. b remains initial struc = VALUE #( a = 2 ). "Explicitly setting an initial value for a component struc = VALUE #( a = 1 b = VALUE #( ) ). "All component values of the first line added are initial itab4 = VALUE #( ( ) ( a = 1 b = 'aaa' ) ). "Initial values can be created for all types, e.g. also for elementary types. "VALUE cannot be used to create elementary data objects and provide concrete "values, however, an empty VALUE expression can be used to create elementary "data objects with type-specific initial values. DATA(int) = VALUE i( ). DATA int2 TYPE i. int2 = VALUE #( ). DATA(xstr) = VALUE xstring( ). ``` |
| `VALUE` constructor used for nested/deep data objects | ``` abap "Creating a nested structure DATA: BEGIN OF nested_struc, a TYPE i, BEGIN OF struct, b TYPE i, c TYPE c LENGTH 3, END OF struct, END OF nested_struc. "Populating a nested structure nested_struc = VALUE #( a = 1 struct = VALUE #( b = 1 c = 'aaa' ) ). "Instead of, for example, using the component selector nested_struc-a = 2. nested_struc-struct-b = 3. nested_struc-struct-c = 'bbb'. "Deep table TYPES deep_itab_type LIKE TABLE OF nested_struc WITH EMPTY KEY. DATA(deep_itab) = VALUE deep_itab_type( ( nested_struc ) "Adding an existing structure ( a = 3 struct = VALUE #( b = 3 c = 'ccc' ) ) ( a = 4 struct = VALUE #( b = 4 c = 'ddd' ) ) ). ``` |
| `BASE` addition | ``` abap "A constructor expression without the BASE addition initializes the target variable. "Therefore, you can use the addition if you do not want to construct a structure or "internal table from scratch but keep existing content. "Populating a structure struc = VALUE #( a = 1 b = 'aaa' ). "struc is not initialized, only component b is modified, value of a is kept struc = VALUE #( BASE struc b = 'bbb' ). "Populating an internal table itab = VALUE #( ( a = 1 b = 'aaa' ) ( a = 2 b = 'bbb' ) ). "Two more lines are added, existing content is preserved, the internal table is not "initialized itab = VALUE #( BASE itab ( a = 3 b = 'ccc' ) ( a = 4 b = 'ddd' ) ). ``` |
| `LINES OF` addition | ``` abap "All or some lines of another table can be included in the target internal table "(provided that they have appropriate line types). "With the LINES OF addition, more additions can be specified. DATA(itab5) = itab. DATA(itab6) = itab. itab = VALUE #( ( a = 1 b = 'aaa' ) ( a = 2 b = 'bbb' ) ( LINES OF itab5 ) "All lines of itab5 ( LINES OF itab6 FROM 2 TO 4 ) ). "Specific lines of itab6 itab = VALUE #( ( LINES OF itab5 STEP 2 ) "Adding every second line ( LINES OF itab6 USING KEY primary_key ) ). "Specifying a table key ``` |
| Short form for internal tables with structured line types | ``` abap "- Assignments of values to individual structure components are possible outside of inner " parentheses "- In that case, all of the following components in the inner parentheses are assigned that " value. "- The assignment is made up to the next explicit assignment for the corresponding component. TYPES: BEGIN OF structype, a TYPE i, b TYPE c LENGTH 3, c TYPE string, END OF structype. TYPES tabtype TYPE TABLE OF structype WITH EMPTY KEY. DATA(itab7) = VALUE tabtype( b = 'aaa' ( a = 1 c = `xxx` ) ( a = 2 c = `yyy` ) b = 'bbb' c = `zzz` ( a = 3 ) ( a = 4 ) ). *A B C *1 aaa xxx *2 aaa yyy *3 bbb zzz *4 bbb zzz "This option can be handy in various contexts, for example, in a "ranges table. TYPES int_tab_type TYPE TABLE OF i WITH EMPTY KEY. "Populating an integer table with values from 1 to 20 (see iteration "expressions with FOR further down) DATA(inttab) = VALUE int_tab_type( FOR x = 1 WHILE x <= 20 ( x ) ). DATA rangetab TYPE RANGE OF i. "Populating a range table using VALUE and the short form rangetab = VALUE #( sign = 'I' option = 'BT' ( low = 1 high = 3 ) ( low = 6 high = 8 ) ( low = 12 high = 15 ) option = 'GE' ( low = 18 ) ). "Using a SELECT statement to retrieve internal table content "based on the range table specifications SELECT * FROM @inttab AS tab WHERE table_line IN @rangetab INTO TABLE @DATA(result). "result: 1, 2, 3, 6, 7, 8, 12, 13, 14, 15, 18, 19, 20 "The following EML statement creates RAP BO instances. The BDEF derived "type is created inline. With the CREATE FROM addition, the %control values "must be specified explicitly. You can provide the corresponding values "for all table lines using the short form instead of individually "specifying the values for each instance. MODIFY ENTITIES OF zdemo_abap_rap_ro_m ENTITY root CREATE FROM VALUE #( %control-key_field = if_abap_behv=>mk-on %control-field1 = if_abap_behv=>mk-on %control-field2 = if_abap_behv=>mk-on %control-field3 = if_abap_behv=>mk-on %control-field4 = if_abap_behv=>mk-off ( %cid = 'cid1' key_field = 1 field1 = 'aaa' field2 = 'bbb' field3 = 10 field4 = 100 ) ( %cid = 'cid2' key_field = 2 field1 = 'ccc' field2 = 'ddd' field3 = 20 field4 = 200 ) ) MAPPED DATA(m) FAILED DATA(f) REPORTED DATA(r). ``` |
| Assigning incompatible structures and internal tables |
- The example makes use of the `BASE` addition, and includes a `CORRESPONDING` expression. Find more additions to `CORRESPONDING` expressions in the section below.
- The `s1` structure is assigned the identically named components of the `s2` structure. Other components are assigned by explicitly specifying them.
- Another example performs an assignment with internal tables, using a table iteration with a `FOR` loop.
``` abap DATA: BEGIN OF s1, comp1 TYPE i, comp2 TYPE i, comp3 TYPE i, comp4 TYPE i, comp5 TYPE i, END OF s1, BEGIN OF s2, comp1 TYPE i VALUE 1, comp2 TYPE i VALUE 2, comp3 TYPE i VALUE 3, END OF s2. s1 = VALUE #( BASE CORRESPONDING #( s2 ) comp4 = 4 comp5 = 5 ). DATA itab1 LIKE TABLE OF s1 WITH EMPTY KEY. DATA itab2 LIKE TABLE OF s2 WITH EMPTY KEY. itab1 = VALUE #( ( comp1 = 1 comp2 = 2 comp3 = 3 comp4 = 4 comp5 = 5 ) ( comp1 = 10 comp2 = 20 comp3 = 30 comp4 = 40 comp5 = 50 ) ( comp1 = 100 comp2 = 200 comp3 = 300 comp4 = 400 comp5 = 500 ) ). itab2 = VALUE #( ( comp1 = 7 comp2 = 8 comp3 = 9 ) ( comp1 = 70 comp2 = 80 comp3 = 90 ) ( comp1 = 700 comp2 = 800 comp3 = 900 ) ). itab1 = VALUE #( BASE itab1 FOR wa IN itab2 ( CORRESPONDING #( wa ) ) ). *Result: *COMP1 COMP2 COMP3 COMP4 COMP5 *1 2 3 4 5 *10 20 30 40 50 *100 200 300 400 500 *7 8 9 0 0 *70 80 90 0 0 *700 800 900 0 0 "Note: If BASE is not specified, the target table is initialized first. "itab1 = VALUE #( FOR wa IN itab2 ( CORRESPONDING #( wa ) ) ). *Result: *COMP1 COMP2 COMP3 COMP4 COMP5 *7 8 9 0 0 *70 80 90 0 0 *700 800 900 0 0 ``` |
| Table iterations with `FOR` |
- Have the semantics of `LOOP AT` statements
- Find more examples [below](#iteration-expressions-using-for)
``` abap TYPES: BEGIN OF s, col1 TYPE c LENGTH 5, col2 TYPE i, col3 TYPE i, END OF s. TYPES itab_type TYPE TABLE OF s WITH EMPTY KEY. DATA(itab) = VALUE itab_type( ( col1 = 'a' col2 = 1 col3 = 30 ) ( col1 = 'bb' col2 = 2 col3 = 10 ) ( col1 = 'ccc' col2 = 3 col3 = 20 ) ). DATA(it1) = VALUE itab_type( FOR wa IN itab ( col1 = wa-col1 && 'z' col2 = wa-col2 + 1 ) ). *Result: *COL1 COL2 COL3 *az 2 0 *bbz 3 0 *cccz 4 0 ``` |
| `LET` expressions |
- They define one or more variables (field symbols are also possible) as local (i.e. local to the expression) helper fields and assigns values to them.
- Find more examples [below](#let-expressions)
``` abap DATA(strtab) = VALUE string_table( LET mark = '!' IN ( |abc{ mark }| ) ( |def{ mark }| ) ( |ghi{ mark }| ) ). *Result: *abc! *def! *ghi! ``` |
| Using data objects declared inline in various ABAP statements |
Using the inline construction of structures and internal tables, you can
avoid the declaration of extra variables in many contexts, for example,
ABAP statements like
[`MODIFY`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapmodify_itab.htm)
for modifying internal tables or [ABAP
SQL](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenabap_sql_glosry.htm "Glossary Entry")
statements like
[`MODIFY`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapmodify_dbtab.htm)
(which is not to be confused with the ABAP statement having the same
name) for modifying database tables.
``` abap "ABAP statements "Modifiying individual internal table entries based on a structure created inline "Modifying a table line MODIFY TABLE some_itab FROM VALUE #( a = 1 ... ). "Inserting a table line INSERT VALUE #( a = 2 ... ) INTO TABLE some_itab. "Deleting a table line DELETE TABLE some_itab FROM VALUE #( a = 3 ). "ABAP SQL statement "Modifying multiple database table entries based on an internal table "constructed inline within a host expression MODIFY zdemo_abap_carr FROM TABLE @( VALUE #( ( carrid = 'XY' carrname = 'XY Airlines' currcode = 'USD' url = 'some_url' ) ( carrid = 'ZZ' carrname = 'ZZ Airways' currcode = 'EUR' url = 'another_url' ) ) ). ``` |
| Grouping lines in internal tables |
- Regarding grouping lines in internal tables, find more information in the [Internal Tables: Grouping](11_Internal_Tables_Grouping.md) cheat sheet.
- More code snippets on grouping lines, covering syntax such as `FOR GROUPS` with the `VALUE` and `REDUCE` operators, are available [below](#grouping-lines-in-internal-tables-with-valuereduce).
``` abap ... DATA(it_val_1) = VALUE string_table( FOR GROUPS gr OF wa IN itab4grp GROUP BY wa-col1 ASCENDING WITHOUT MEMBERS ( |{ gr }| ) ). ``` |
| Subject | Notes/Code Snippet |
| Explicit conversion |
``` abap
"Result: 0.2
DATA(conv_res) = CONV decfloat34( 1 / 5 ).
"Comparison with an expression without CONV
"The result is 0, the data type is i.
DATA(res) = 1 / 5.
"Example with internal table types
TYPES inttab_type TYPE TABLE OF i WITH EMPTY KEY.
DATA itab TYPE SORTED TABLE OF i WITH NON-UNIQUE DEFAULT KEY.
FIELD-SYMBOLS |
| Constructing data objects |
As outlined above, you can construct structures and internal
tables using the `VALUE` operator. Using `VALUE` for
constructing [elementary data objects](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenelementary_data_object_glosry.htm "Glossary Entry") and providing values is not possible. You can only use it to create a data object with an initial value, for example `DATA(str) = VALUE string( ).`. The `CONV` operator closes this gap.
``` abap DATA(a) = CONV decfloat34( '0.4' ). "Instead of DATA b TYPE decfloat34 VALUE '0.4'. "or DATA c TYPE decfloat34. c = '0.4'. "Using the VALUE operator to construct elementary data objects "and provide values is not possible. "It is only possible to create an elementary data object with "an initial value. DATA(d) = VALUE string( ). "This way it basically corresponds to a declaration as follows, "which does not specify a start value with the addition VALUE. DATA e TYPE string. "Redundant conversion "The variable derives the type (string) automatically from the "literal with the backquotes on the right-hand side. DATA(f) = `hallo`. "Produces a syntax warning "DATA(g) = CONV string( `hallo` ). ``` |
| Subject | Notes/Code Snippet |
| Lossless assignments | ``` abap "Note: An assignment is made in accordance with conversion rules. Check "the ABAP Keyword Documentation for these rules. An assignment is only "made if no values are lost. Otherwise, an error occurs. Either it is "detected by static code checks or at runtime raising a catchable exception. TYPES clen3 TYPE c LENGTH 3. DATA(as1) = EXACT clen3( abap_true ). DATA(as2) = EXACT clen3( 'XY' ). "DATA(as3) = EXACT clen3( 'abcd' ). "Catching exception TRY. DATA(as4) = EXACT clen3( 'abcd' ). CATCH cx_sy_conversion_data_loss. ENDTRY. ``` |
| Lossless calculations | ``` abap "The first statement works, whereas the second statement raises an exception. "A rounding to two decimal places is required. TYPES packednum TYPE p LENGTH 8 DECIMALS 2. DATA(calc1) = EXACT packednum( 1 / 4 ). "DATA(calc2) = EXACT packednum( 1 / 3 ). "Catching exceptions when rounding in lossless calculations TRY. DATA(calc3) = EXACT packednum( 1 / 3 ). CATCH cx_sy_conversion_rounding. ENDTRY. ``` |
| Subject | Notes/Code Snippet |
| Creating a result depending on logical expressions | ``` abap DATA(day_or_night) = COND #( WHEN cl_abap_context_info=>get_system_time( ) BETWEEN '050000' AND '220000' THEN `day` ELSE `night` ). "A constructor expression as above instead of, for example, an IF statement as follows. IF cl_abap_context_info=>get_system_time( ) BETWEEN '050000' AND '220000'. day_or_night = `day`. ELSE. day_or_night = `night`. ENDIF. ``` |
| Multiple logical expressions initiated by `WHEN`, using `LET` | ``` abap DATA(time_of_day) = COND #( LET time = cl_abap_context_info=>get_system_time( ) IN WHEN time BETWEEN '050001' AND '120000' THEN |Good morning, it's { time TIME = ISO }.| WHEN time BETWEEN '120001' AND '180000' THEN |Good afternoon, it's { time TIME = ISO }.| WHEN time BETWEEN '180001' AND '220000' THEN |Good evening, it's { time TIME = ISO }.| ELSE |Good night, it's { time TIME = ISO }.| ). ``` |
| `THROW` addition to raise an exception | ``` abap "THROW addition to raise an exception (working like RAISE EXCEPTION TYPE statements) "by specifying an exception class "Note: It is possible to ... "- specify the THROW addition also after THEN. "- make exceptions resumable using the RESUMABLE addition. DATA(num1) = 0. DATA(num2) = 0. TRY. "The example raises the exception because both operands have the value 0. DATA(div) = COND decfloat34( WHEN num1 <> 0 AND num2 <> 0 THEN num1 / num2 WHEN num1 = 0 AND num2 <> 0 THEN num1 / num2 ELSE THROW cx_sy_zerodivide( ) ). CATCH cx_sy_zerodivide. DATA(two_zeros) = `Zero division`. ENDTRY. "Excursion for the example above: The following statement does not result in an "error in ABAP (zero division 'allowed' if the first operand has also the value 0). div = 0 / 0. ``` |
| `THROW SHORTDUMP` addition to raise a runtime error | ``` abap "THROW SHORTDUMP addition to raise a runtime error (working like RAISE SHORTDUMP "TYPE statements) by specifying an exception class; a message can be also passed, "and input parameters can be filled DATA(int1) = 0. DATA(int2) = 0. DATA(division) = COND decfloat34( WHEN int1 <> 0 AND int2 <> 0 THEN int1 / int2 WHEN int1 = 0 AND int2 <> 0 THEN int1 / int2 ELSE THROW SHORTDUMP cx_sy_zerodivide( ) ). ``` |