1

In sap I have a table, there are rows with the same name but with different quantity. I want to summarize this rows like this:

    SELECT c~aufnr
           p~matnr p~bdter p~meins p~baugr p~dbskz p~erfmg p~aufnr
           f~maktx
       INTO CORRESPONDING FIELDS OF TABLE it_tab
       FROM  afpo AS c
         INNER JOIN resb AS p ON c~aufnr = p~aufnr
         INNER JOIN makt AS f ON p~matnr = f~matnr.             

    LOOP AT it_tab INTO fs_tab.
       COLLECT fs_tab INTO it_tab_collected.
    ENDLOOP.
    it_tab = it_tab_collected.

But in this case it sums only absolutelly identically rows. I need to sum up rows only with the same name.

How can I achieve this?

Regards, Alexander.

Sandra Rossi
  • 11,934
  • 5
  • 22
  • 48
alexander.skibin
  • 133
  • 1
  • 2
  • 15

3 Answers3

4

As icbytes already said, COLLECT uses the key fields to determine which fields to aggregate. I would suggest defining some data types to match your scenarion:

TYPES: BEGIN OF t_my_type,
         key_a TYPE foo,
         key_b TYPE foo,
         nokey_c TYPE foo,
         nokey_d TYPE foo,
       END OF t_my_type,
       tt_my_type_list TYPE STANDARD TABLE OF t_my_type WITH DEFAULT KEY,
       tt_my_type_hash TYPE HASHED TABLE OF t_my_type WITH KEY key_a key_b.

DATA: lt_result TYPE tt_my_type_list,
      lt_sums   TYPE tt_my_type_hash.

FIELD-SYMBOLS: <ls_result> TYPE t_my_type.

LOOP AT lt_result ASSIGNING <ls_result>.
  COLLECT <ls_result> INTO lt_sums.
ENDLOOP.

...or you might want to use an aggregate function in the first place...

vwegert
  • 18,371
  • 3
  • 37
  • 55
2

I'd stick away from COLLECT, even tho you can save a few lines of code, there's no need to use it and adds restrains for no reason.

I've had problems to maintain/add features to previously written code that used COLLECT because it doesn't allow non-key non-numeric fields to be added to the internal tables and sometimes I've been forced to modify a lot of COLLECT sentences or introduce unnecessary complexity to the code (like using extra internal tables).

Example (taking vwegert's example as a base, who did a good job explaining how to use COLLECT correctly):

TYPES: BEGIN OF t_my_type,
         key_a TYPE foo,
         key_b TYPE foo,
         """ with COLLECT all 'foo' types **has to be** numeric
         nokey_c TYPE foo,
         nokey_d TYPE foo,
         """ if you ever need to add something like a note field to the table
         """ you'll find out that you have to change all the COLLECT sentences
         """ because this new field wouldn't let the code compile
         nokey_notes(50) type c,
       END OF t_my_type,

       tt_my_type_list TYPE STANDARD TABLE OF t_my_type WITH DEFAULT KEY,
       tt_my_type_hash TYPE HASHED TABLE OF t_my_type WITH KEY key_a key_b.

DATA: lt_result TYPE tt_my_type_list,
      lt_sums   TYPE tt_my_type_hash.

FIELD-SYMBOLS: <ls_result> TYPE t_my_type.


""" just imagine you need the 'nokey_notes' field for an ALV for user input.
PERFORM show_alv USING lt_result.


""" and you don't care about this new field when doing
""" the sum/average or whatever you are trying to calculate
""" well, it won't work with COLLECT...
LOOP AT lt_result ASSIGNING <ls_result>.
  COLLECT <ls_result> INTO lt_sums.
ENDLOOP.

My recommendation would be using AT... ENDAT (besides SELECT's aggregate functions, which is a good option, specially if you don't need the individual data).

Of course the code will gain a few extra lines, but in my opinion/experience they are worth it, because the code will be easier to maintain in the future.

TYPES: BEGIN OF t_my_type,
         key_a TYPE foo,
         key_b TYPE foo,
         """ with COLLECT all 'foo' types **has to be** numeric
         nokey_c TYPE foo,
         nokey_d TYPE foo,
         """ without COLLECT you are able to add new non-key non-numeric fields
         nokey_notes(50) type c,
       END OF t_my_type,

       tt_my_type_list TYPE STANDARD TABLE OF t_my_type.

DATA: lt_result TYPE tt_my_type_list,
      lt_sum    TYPE tt_my_type_list.
      lwa_sum   TYPE t_my_type.

FIELD-SYMBOLS: <ls_result> TYPE t_my_type.


""" just imagine you need the 'nokey_notes' field for an ALV for user input.
PERFORM show_alv USING lt_result.


""" sorting is important when using AT... ENDAT, there are other gotchas too
""" make sure you read its documentation carefully if you never used it
""" (like everything right? :P)
SORT lt_result BY key_a key_b.
REFRESH lt_sum.

""" and you don't care about 'nokey_notes' field when doing calculation
LOOP AT lt_result ASSIGNING <ls_result>.

  AT NEW key_b.
    """ this get executed when the work area's primary keys
    """ change, good time to prepare the lwa_sum work area.
    CLEAR lwa_sum.
    lwa_sum-key_a = lwa_sum-key_a.
    lwa_sum-key_b = lwa_sum-key_b.
  ENDAT.

  """ do whatever math/logic is need with the fields
  lwa_sum-nokey_c = lwa_sum-nokey_c + <ls_result>-nokey_c.
  lwa_sum-nokey_d = lwa_sum-nokey_d + <ls_result>-nokey_d.

  AT END OF key_b.
    """ this get executed when the work area's primary keys
    """ is about to change (in next iteration) or at the last
    """ record of the table
    """ good place to save the results to a new internal table
    APPEND lwa_sum to lt_sums.
  ENDAT.

ENDLOOP.
KurzedMetal
  • 12,540
  • 6
  • 39
  • 65
0

AFAIK collect uses keys as it can decide which rows shall create an aggregate. If You have other character-values prepending numerical values, delete them in another itab, so that the only c-like column, which is filled, will be the "name". This will serve as the only key to let abap processor aggregate.

Did that help ?

icbytes
  • 1,831
  • 1
  • 17
  • 27