The REDUCE statement in ABAP is a newer, more performant way of grouping numbers, strings and of course tables without nested looping and declaring too many additional helping variables.
In this post I am going to give some simple theorethical examples with numbers and strings and one more business related example.
- Simple Sum
This is a rather theorethical example, that will help us understand the syntax. Here we want to sum the numbers from 1 to 100.
The result is the variable lv_i of type i.
The sum is in the variable s and is only valid in the reduce statement.
j is our counter and so we go.Execute and you will get 5050 .
data(lv_i) = reduce i( init s = 0
for j = 1 until j > 100
next s = s + j ).
for j = 1 until j > 100
next s = s + j ).
- String operation
This is another theorethical example. It demonstrates that we can use the reduce statement for non-arithmetic operations.
DATA(lv_text) = REDUCE string( INIT text = | |
FOR t = |AB| THEN t && |0|
UNTIL strlen( t ) > 10
NEXT text = text && |{ t }| && |,| ).
FOR t = |AB| THEN t && |0|
UNTIL strlen( t ) > 10
NEXT text = text && |{ t }| && |,| ).
The result is:
- Business-related example
Let us take an example from the accounting and assume that we want to sum the amounts per trading partner. For simplicity, we will do this in one company code.
This is what my code would look like by using the old LOOP AT NEW statement:
TYPES: BEGIN OF ty_sum,
* bukrs TYPE bukrs,
vbund TYPE rassc,
dmbtr TYPE dmbtr,
END OF ty_sum.
DATA: lt_sum TYPE SORTED TABLE OF ty_sum WITH UNIQUE KEY vbund,
ls_sum TYPE ty_sum.
TYPES: BEGIN OF ty_bsis,
vbund TYPE bsis-vbund,
bukrs TYPE bsis-bukrs,
gjahr TYPE bsis-grant_nbr,
belnr TYPE bsis-belnr,
shkzg TYPE bsis-shkzg,
dmbtr TYPE bsis-dmbtr,
END OF ty_bsis.
DATA lt_bsis TYPE SORTED TABLE OF ty_bsis WITH NON-UNIQUE KEY vbund.
SELECT vbund, bukrs, gjahr, belnr, shkzg, dmbtr FROM bsis INTO CORRESPONDING FIELDS OF TABLE @lt_bsis
WHERE bukrs EQ 'XXXX' AND gjahr = '????' AND vbund NE @space.
CHECK lines( lt_bsis ) > 0.
GET RUN TIME FIELD tstart.
LOOP AT lt_bsis INTO DATA(ls_bsis).
AT NEW vbund.
ls_sum-vbund = ls_bsis-vbund.
LOOP AT lt_bsis ASSIGNING FIELD-SYMBOL(<fs_bsis>) WHERE vbund = ls_bsis-vbund.
ls_sum-dmbtr = ls_sum-dmbtr + COND dmbtr( WHEN <fs_bsis>-shkzg EQ 'S' THEN <fs_bsis>-dmbtr ELSE <fs_bsis>-dmbtr * -1 ).
ENDLOOP.
APPEND ls_sum TO lt_sum.
CLEAR ls_sum.
ENDAT.
ENDLOOP.
* Record end time
GET RUN TIME FIELD tstop.
trun = ( tstop - tstart ).
* bukrs TYPE bukrs,
vbund TYPE rassc,
dmbtr TYPE dmbtr,
END OF ty_sum.
DATA: lt_sum TYPE SORTED TABLE OF ty_sum WITH UNIQUE KEY vbund,
ls_sum TYPE ty_sum.
TYPES: BEGIN OF ty_bsis,
vbund TYPE bsis-vbund,
bukrs TYPE bsis-bukrs,
gjahr TYPE bsis-grant_nbr,
belnr TYPE bsis-belnr,
shkzg TYPE bsis-shkzg,
dmbtr TYPE bsis-dmbtr,
END OF ty_bsis.
DATA lt_bsis TYPE SORTED TABLE OF ty_bsis WITH NON-UNIQUE KEY vbund.
SELECT vbund, bukrs, gjahr, belnr, shkzg, dmbtr FROM bsis INTO CORRESPONDING FIELDS OF TABLE @lt_bsis
WHERE bukrs EQ 'XXXX' AND gjahr = '????' AND vbund NE @space.
CHECK lines( lt_bsis ) > 0.
GET RUN TIME FIELD tstart.
LOOP AT lt_bsis INTO DATA(ls_bsis).
AT NEW vbund.
ls_sum-vbund = ls_bsis-vbund.
LOOP AT lt_bsis ASSIGNING FIELD-SYMBOL(<fs_bsis>) WHERE vbund = ls_bsis-vbund.
ls_sum-dmbtr = ls_sum-dmbtr + COND dmbtr( WHEN <fs_bsis>-shkzg EQ 'S' THEN <fs_bsis>-dmbtr ELSE <fs_bsis>-dmbtr * -1 ).
ENDLOOP.
APPEND ls_sum TO lt_sum.
CLEAR ls_sum.
ENDAT.
ENDLOOP.
* Record end time
GET RUN TIME FIELD tstop.
trun = ( tstop - tstart ).
The same with REDUCE:
The filter statement generates an internal with the desired records only, so that we can avoid the LOOP AT ...WHERE situation above.
LOOP AT lt_sum ASSIGNING FIELD-SYMBOL(<fs_sum_>).
<fs_sum_>-dmbtr = REDUCE dmbtr( INIT val TYPE dmbtr
FOR ls_bsis_r IN
FILTER #( lt_bsis
WHERE vbund EQ <fs_sum_>-vbund )
NEXT val = val + COND dmbtr( WHEN ls_bsis_r-shkzg EQ 'S' THEN ls_bsis_r-dmbtr
ELSE ls_bsis_r-dmbtr * -1 ) ).
WRITE: <fs_sum_>-vbund, <fs_sum_>-dmbtr . NEW-LINE.
ENDLOOP.
<fs_sum_>-dmbtr = REDUCE dmbtr( INIT val TYPE dmbtr
FOR ls_bsis_r IN
FILTER #( lt_bsis
WHERE vbund EQ <fs_sum_>-vbund )
NEXT val = val + COND dmbtr( WHEN ls_bsis_r-shkzg EQ 'S' THEN ls_bsis_r-dmbtr
ELSE ls_bsis_r-dmbtr * -1 ) ).
WRITE: <fs_sum_>-vbund, <fs_sum_>-dmbtr . NEW-LINE.
ENDLOOP.
The result is cleaner and more performant code!