Replace the LOOP for REDUCE operator
Calm! Don’t hit me. I exaggerated in the title, but it isn’t at all a lie. I don’t want to stay repeating Horst Keller, but some ABAPers still come to me: “I never had to use REDUCE…”
An expression with the REDUCE reduction operator creates a result of a specified data type using the type of one or more condition expressions.
A new and more performative way to not use LOOP AT NEW, for example ( ok ok .. is very old ).
With REDUCE it is possible to do a mathematical operation grouping by the items of a certain table for example. That is, instead of making a LOOP inside LOOP between two tables, you can use REDUCE to directly access the items you need to read. The reading is based on a table, so you can use the FILTER operator, for example, to generate the internal table with only the desired items. See the example below:
REPORT ysamplelkp_reduce.
*------------------------------------------------*
* PURPOSE: For each order item, calculate
* the total value from the KOMV table
* (Conditions) where:
* Condition PBXX = value X
* Condition RA01 = value Y
*
* TOTAL / ITEM (NETWR) = Sum PBXX + Sum RA01
*------------------------------------------------*
CLASS demo DEFINITION.
PUBLIC SECTION.
CLASS-METHODS main.
ENDCLASS.
CLASS demo IMPLEMENTATION.
METHOD main.
TYPES:
BEGIN OF y_ekpo,
ebeln TYPE ekpo-ebeln,
ebelp TYPE ekpo-ebelp,
netwr TYPE ekpo-netwr,
END OF y_ekpo,
yt_ekpo TYPE SORTED TABLE OF y_ekpo
WITH UNIQUE KEY ebeln ebelp,
BEGIN OF y_komv,
knumv TYPE komv-knumv,
kposn TYPE komv-kposn,
kschl TYPE komv-kschl,
kwert TYPE komv-kwert,
END OF y_komv,
yt_komv TYPE SORTED TABLE OF y_komv
WITH NON-UNIQUE KEY knumv kposn kschl
WITH NON-UNIQUE SORTED KEY key_kposn COMPONENTS kposn kschl.
DATA it_ekpo TYPE yt_ekpo.
DATA it_komv TYPE yt_komv.
it_ekpo =
VALUE #(
( ebeln = '0040000000' ebelp = '10' )
( ebeln = '0040000000' ebelp = '20' )
( ebeln = '0040000000' ebelp = '30' )
).
it_komv =
VALUE #(
( knumv = '0000000001' kposn = '10' kschl = 'RA01' kwert = '10.00' )
( knumv = '0000000001' kposn = '10' kschl = 'PBXX' kwert = '350.00' )
( knumv = '0000000001' kposn = '20' kschl = 'RA01' kwert = '2.00' )
( knumv = '0000000001' kposn = '20' kschl = 'RA01' kwert = '3.50' )
( knumv = '0000000001' kposn = '20' kschl = 'PBXX' kwert = '400.00' )
( knumv = '0000000001' kposn = '10' kschl = 'RA01' kwert = '5.00' )
( knumv = '0000000001' kposn = '10' kschl = 'PBXX' kwert = '200.00' )
).
DATA(out) = cl_demo_output=>new( )->write_data( it_ekpo ).
out->write_data( it_komv ).
*------------------------------------------------*
* Using LOOP and Work area (on purpose)
*------------------------------------------------*
DATA st_ekpo LIKE LINE OF it_ekpo.
DATA st_ekpox LIKE LINE OF it_ekpo.
DATA st_komv LIKE LINE OF it_komv.
LOOP AT it_ekpo
INTO st_ekpo.
st_ekpox = st_ekpo.
AT NEW ebelp.
LOOP AT it_komv
INTO st_komv
USING KEY key_kposn
WHERE kposn EQ st_ekpox-ebelp.
st_ekpo-netwr = st_ekpo-netwr + st_komv-kwert.
ENDLOOP.
MODIFY it_ekpo FROM st_ekpo TRANSPORTING netwr.
ENDAT.
ENDLOOP.
out->write_text( 'Using LOOP and Work area:' ).
out->write_data( it_ekpo ).
*------------------------------------------------*
* Using REDUCE ( It's beautiful! )
*------------------------------------------------*
LOOP AT it_ekpo
ASSIGNING FIELD-SYMBOL(<fs_ekpo>).
<fs_ekpo>-netwr = REDUCE netwr( INIT val TYPE netwr
FOR wa IN
FILTER #( it_komv
USING KEY key_kposn
WHERE kposn EQ CONV #( <fs_ekpo>-ebelp ) )
NEXT val = val + wa-kwert ).
ENDLOOP.
out->write_text( 'Using REDUCE:' ).
out->write_data( it_ekpo )->display( ).
ENDMETHOD.
ENDCLASS.
START-OF-SELECTION.
demo=>main( ).
Giving…
REDUCE:
This is a simple example. Probably I can get the same result without using LOOP in any way ( it’s for you to think ). For me, it’s a very clean code. For more details, I recommend a read on at Help SAP for Iteration Expressions.
Hugs!
Hello Douglas,
while checking your use case for REDUCE, I kept thinking AT NEW was to be replaced by GROUP BY, so I tried...
and it actually passes the test.
Why am I not using REDUCE more? Maybe because there are always alternatives and the result is not seem beautiful in my eyes. Look at this code
It has special routines in the LOOP to encapsulate side effects, it is my attempt to make it expression oriented. Now will I get any benefit form re-implementing the routines for the NEXT part of the REDUCE statement? I will have to try...
regards,
JNN
Hi JNN,
Currently, this is the beauty of ABAP. We can use the new syntax to write elegant code in many ways. I made a simple code to exemplify REDUCE.
I would say no. But it doesn't prevent new codes from being written like this. If ABAP evolves, we have to keep up.
Thank you JNN, for your recognition and support.
Regards
Douglas
Hi Douglas,
Works only if it_komv is sorted table. What is IT_komv is not sorted table.
regards,
Manish
Hi Manish,
The IT_KOMV makes reference to the type: YT_KOMV TYPE SORTED TABLE OF Y_KOMV.
Regards,
Douglas
Hi Douglas,
I copied you code and tried to activate it I am getting an error that FILTER ANY( ) is not any internal table.
Can you please let me know the reason for this.
Is the Filter constructor is returning an internal table ?
And also in the LOOP inside LOOP we are adding each Condition value(KWERT) in KOMV table to Net PO value(NETWR) in EKPO table
st_ekpo-netwr = st_ekpo-netwr + st_komv-kwert.
but we are not adding in Reduce Constructor we are just adding to initial VAL and.
val = val + wa-kwert
Can you please tell me the difference from where the calue of netwr value is added ?
Thanks
Pawan Akella
Hi Pawan.
What's your version of the SAP_ABA component? The new Filter operator came with ABAP News for 7.40, SP08.
Yes.
This section...
... the FILTER returned a internal table, like this (first round)...
...and the NEXT uses the WA for work area for each row in the table.
Regards.
Douglas.
Hello,
For Error 'FILTER ANY( ) is not any internal table'. Replace '#' with table type, here it is YT_KOMV.
Regards,
Vikesh.
Hello
I would like to add something also about for loop. We can use for loop instead of Loop at even if you have more than one loop by using Reduce for some operation like sum.
Best regards
Hi Experts,
Can you guys please provide an example in which you have two or more nested loops and filling a third internal table? I mean, how can I translate the following nested loop into ABAP 7.4 FOR Iteration Expression?
LOOP AT it_tempo INTO <fs_tempo>.
CLEAR wa_result.
MOVE-CORRESPONDING <fs_tempo> TO wa_result.
wa_result-pur_orders = wa-pur_orders.
wa_result-unrestricted_stck = wa-unrestricted_stck.
LOOP AT it_marc ASSIGNING <fs_marc> WHERE matnr = <fs_tempo>-matnr AND
werks = p_werks AND
lvorm = space.
wa_result-werks = <fs_marc>-werks.
READ TABLE it_makt ASSIGNING <fs_makt> WITH KEY matnr = <fs_tempo>-matnr
spras = sy-langu.
IF sy-subrc = 0.
wa_result-maktx = <fs_makt>-maktx.
ENDIF.
READ TABLE it_t023t ASSIGNING <fs_t023t> WITH KEY matkl = <fs_tempo>-matkl
spras = sy-langu.
IF sy-subrc = 0.
wa_result-wgbez = <fs_tempo>-wgbez.
ENDIF.
LOOP AT it_eina ASSIGNING <fs_eina> WHERE matnr = <fs_tempo>-matnr AND
loekz = ' '.
wa_result-lifnr = <fs-eina>-lifnr.
LOOP AT it_eine ASSIGNING <fs_eine> WHERE infnr = <fs_eina>-infnr AND
loekz = ' '.
wa_result-netpr = <fs_eine>-netpr.
IF <fs_eine>-peinh = 0.
wa_result-peinh = 1.
ELSE.
wa_result-peinh = <fs_eine>-peinh.
ENDIF.
APPEND wa_result TO ti_result.
ENDLOOP.
CLEAR: wa_result-lifnr, wa_result-name1.
ENDLOOP.
ENDLOOP.
ENDLOOP.
***********************************************
I'll be thankful if you can help me out with this big issue I have.
Carlos.
Hello,
Thank you for sharing this valuable blog.
I would like to know one thing related to this, when I am using same internal table then, I am getting BCD compute overflow as the output length of BSEG-WRBTR is 16(I am using WRBTR to reduce in same internal and sum up), so giving error when addition is more than 16 digits.
Thanks,
Sayan
Hello Douglas Santos
Thank you for your blog.
I tried to activate a program with a simple example of REDUCE but received error
Field "REDUCE" is unknown. It is neither in one of the specified tables
nor defined by a "DATA" statement. "DATA" statement.
The code is:
cl_demo_output=>display(
REDUCE i( INIT s = 0
FOR i = 1 UNTIL i > 10
NEXT s = s + i ) ).
My version is:
Could you please tell me what is the problem?
Thank you in advanced
Hagit
Hello,
your System has SP07 SP08 is needed.
Jens Seifert ,
Thank you for your reply.
Hagit