Skip to Content

As we all know, the In-line declarations, operators and expressions available in 7.4 SP02 onward are taking the abap world by storm for last few years. For the new or the experienced abap-ers this is almost like fall ‘in-line’ or fall apart. 🙂 The main idea is to write code easily, keep it lean and compact as much as possible.

But there is no end of debate that if the old school abap code is good enough to achieve everything then why complicate life ?Well with all that being said let us discuss about some simple best case scenarios of FOR expression which can seriously reduce no of lines of code and make it more compact. I feel this is one of the best addition among the new features ( Remembering old friend Mr. ‘C’ 😉 ).

Situation 1: To move values from a source internal table to a target internal table which has all the fields of source internal table + some additional fields ( say ). 

*Define structure
  BEGIN OF ty_struct1,
    field1 TYPE i,
    field2 TYPE string,
  END OF ty_struct1,
  BEGIN OF ty_struct2,
    field1 TYPE i,
    field2 TYPE string,
    field3 TYPE i,
  END OF ty_struct2.

*Define table types
        gtt_struct2 TYPE STANDARD TABLE OF ty_struct2 WITH DEFAULT KEY.

* Initialize source table with some random values
DATA(lt_source) = VALUE gtt_struct1(
    ( field1 = 1 field2 = 'A' )
    ( field1 = 2 field2 = 'B' ) ).

DATA(lt_target1) = VALUE gtt_struct2( FOR lwa_source IN lt_source ( CORRESPONDING #( lwa_source ) ) ).
cl_demo_output=>display( lt_target1 ).

*Populate sy-tabix in the additional fields within the for loop
DATA(lt_target2) = VALUE gtt_struct2( FOR lwa_source IN lt_source
                            INDEX INTO index
                            LET base = VALUE ty_struct2( field3 = index )
                            IN ( CORRESPONDING #( BASE ( base ) lwa_source ) ) ).
cl_demo_output=>display( lt_target2 ).

*Populate any value or call custom method  in the additional fields within the for loop
DATA(lt_target3) = VALUE gtt_struct2( FOR lwa_source IN lt_source
             LET base = VALUE ty_struct2( field3 = 10 ) "<<< Custom method/any value
             IN ( CORRESPONDING #( BASE ( base ) lwa_source ) ) ).
cl_demo_output=>display( lt_target3 ).


Points to Note:

i) VALUE (Type of the internal table) is used for the in-line declaration of the internal table. Here structure and Type declaration is required before using VALUE operator. If you want to use VALUE # then type of the table must be already available and defined in the program i.e. the internal table need to be declared before.

iii)LT_TARGET3-FIELD3 is populated with a hard coded value 10 but in real life a custom method call can also be done in this place to pass the actual value of field3

Situation 2: Suppose we have an internal table and we want to create another range table with the values of one particular field from that internal table 

Sample code

*Get details from DB table
  INTO TABLE @DATA(lt_sflight)
  WHERE connid IN (17,555).

IF sy-subrc = 0.
*Prepare a range table
  DATA: lr_carrid  TYPE RANGE OF s_carr_id.
  lr_carrid = VALUE #( FOR ls_value IN lt_sflight ( sign = 'I'
                                                   option = 'EQ'
                                                   low = ls_value-carrid ) ).
  SORT lr_carrid BY low.
  cl_demo_output=>display( lr_carrid ).


Points to Note:

i) ‘@’ need to be used in the SELECT for in-line declaration of the internal table

Situation 3: There are 2 tables and based on which a third table need to be constructed 

*Define the structures of header & item table
  BEGIN OF comp,
    ebeln TYPE ebeln,
    bukrs TYPE bukrs,
  END OF comp.

*Declare table type
       gtt_item   TYPE SORTED TABLE OF ekpo WITH NON-UNIQUE KEY ebeln
                               WITH NON-UNIQUE SORTED KEY key_combi COMPONENTS ebeln.

*Populate dummy values
DATA(lt_header) = VALUE gtt_header(
                      ( ebeln = '4500000027' )
                      ( ebeln = '4500000028' )
                      ( ebeln = '4500000029' ) ).

DATA(lt_item) = VALUE gtt_item( ( ebeln = '4500000027' ebelp = '000010' netwr = '100' bukrs = 'IND' )
                    ( ebeln = '4500000027' ebelp = '000020' netwr = '200' bukrs = 'IND' )
                    ( ebeln = '4500000027' ebelp = '000030' netwr = '300' bukrs = 'IND' )
                    ( ebeln = '4500000028' ebelp = '000010' netwr = '999' bukrs = 'USA' )
                    ( ebeln = '4500000029' ebelp = '000010' netwr = '25' bukrs = 'GB' )
                    ( ebeln = '4500000029' ebelp = '000020' netwr = '50' bukrs = 'GB' )
                    ( ebeln = '4500000029' ebelp = '000030' netwr = '100' bukrs = 'GB' )
                    ( ebeln = '4500000029' ebelp = '000040' netwr = '150' bukrs = 'GB' ) ).

*Now populate the values of Compor from item table to a new table
DATA(lt_comp) = VALUE gtt_comp(
                    FOR ls_header IN lt_header
                    FOR ls_item IN lt_item WHERE ( ebeln = ls_header-ebeln )
                    (  ebeln = ls_header-ebeln
                       bukrs = ls_item-bukrs ) ).

SORT lt_comp BY ebeln.

cl_demo_output=>display( lt_comp ).


Points to note

i) VALUE (Type of the internal table) is used for the in-line declaration of the internal table.

Situation 4: Summation of item values and populate the total in header table 

  • Use the code from situation 3 for the declaration part
*Now sum up all the netwr for a particular purchase order
  <lfs_comp>-netwr = REDUCE netwr( INIT lv_netwr TYPE netwr
                       FOR ls_item IN
                       FILTER #( lt_item
                       USING KEY key_combi
                       WHERE ebeln = <lfs_comp>-ebeln )
                       NEXT lv_netwr = lv_netwr + ls_item-netwr ).

cl_demo_output=>display( lt_comp ).


Points to note:

i) LT_ITEM has to be sorted table for using the FILTER option

ii) REDUCE with FOR is like a nested loop only difference is that you can’t debug all the iterations

Situation 5: Append new values into an internal table which already have some values 

  • Use the code from situation 3 for the declaration part
*Append new records in item table
lt_item = VALUE #( BASE lt_item
          ( ebeln = '4500000030' ebelp = '000010' netwr = '1099' bukrs = 'CAN' ) ).

cl_demo_output=>display( lt_item ).


Points to Note:

i) Here VALUE with # has been used since type of LT_ITEM is already defined

All the above 5 examples are simple and self explanatory. If you try them in your system I am sure it will be easier to grasp. If you have any questions let me know. There are tons of feature added with the new expressions and operators. Please feel free to add any other good use of FOR expression, if I have missed. I am planning to write more in this space like when to use FOR ( New ABAP ) and when to use LOOP ( old abap ) and related topics in future.

Acknowledgement: By Horst Keller

To report this post you need to login first.


You must be Logged on to comment or reply to a post.

  1. Roberto Vacca

    Nice blog. Very nice way to solve the 10.000 rows of old-school coding style, even though FIELD-SYMBOLS are already a very powerful instrument like pointers in C, and many others instructions in ABAP too.

    I like it but sincerely we’ve a problem all over that.

    Even if we can try to complicate code specifics to protect real coders from newbies and parasites, we will never be able to make CTRL+C & CTRL+V illegal.

    So, dear friends, this is totally unuseful against human being capacity to study how to avoid a job .

    Someone will have to learn this new style and working hard to make it a standard way to code and someone else will have always a  ready soup .. what’s the difference? 🙂

    In my opinion this is not a real evolution , but a way to create jobs and that’s ok too  I suppose 🙂





    1. Atanu Mukherjee Post author

      I don’t think it will ever replace the old school abap completely. Just that you have to know where to use what to make life easier. Also if some one does copy paste he has to understand the application otherwise troubleshooting will be difficult. Isn’t it? 🙂

      1. Roberto Vacca

        Yes  sure will be difficult but only for who have fixed term contracts and the new generations that will have to rebuild all this garbage . and furthermore they still have to use old programming style, perhaps a little cleaner, because old generations, with more job rights, do not want to know how to learn 🙁

  2. Michelle Crapo

    <Sigh>   There are always people that will tell me the old way is better.   I don’t think the “old” way should be thrown away.   There are some take forward things…    But suppose we didn’t change the way we developed.   Who would want to be developing with punch cards?   Machine language only?  We have to evolve.  Copy / paste is just too easy.

    However, I’m keeping this blog in my back pocket.      It is worth it to try to show people the advantages.

    It’s a hard balance for me to achieve.   I love new tools and/or ways of doing things are like a new universe to explore.   I can’t wait to get my hands on the new toys.   Lately there have been huge advantages to watching and adapting to the new tools.   I can’t use them yet, but soon……..

    It comes down to a hard question for me.   I want to do it because is fun vs. I want to do it because of the functional benefits.   This blog will help the discussion along.

    Thank you!

    1. Atanu Mukherjee Post author

      Glad that you liked my blog. I just feel that the new features need to be used prudently and not blindly. If there is a small calculation based loop or simple table population then FOR expression is best to be used. But one disadvantage is that its bit dodgy to debug each iteration of FOR which is possible in normal LOOP..ENDLOOP.  Anyway good luck with your journey with the new sure you will enjoy it.

  3. Daniel Gent

    First, thanks for your informatiove blog.

    Regarding scenario 2:

    Lately I like to use this pattern to generate a range table from DB values:

    CONSTANTS lc_sign_i    TYPE ddsign   VALUE 'I'.
    CONSTANTS lc_option_eq TYPE ddoption VALUE 'EQ'.
    TYPES rng_carrid TYPE RANGE OF s_carrid.
    DATA(lt_rng_carrid) = VALUE rng_carrid( ).
      @lc_sign_i     AS sign,
      @lc_option_eq  AS option,
      carrid         AS low,
      @space         AS high
      INTO TABLE @lt_rng_carrid
      FROM sflight
      WHERE connid IN ( 17, 555 )



    1. Joachim Rees

      Yeah, very helpfull indeed!

      I was wondering if that could also be done with inline-declaration – at first it looks as this might be the case, but no, that’s not a propper range table created that way:


Leave a Reply