ABAP Group Operations in Internal Tables
Today, we will be inspecting some cool grouping techniques introduced in ABAP 7.40.
First, let’s get familiar with our context. We will read the table T001K, where BWKEY (valuation area) is the table key, but BUKRS (company code) is repeated multiple times in various lines. Let’s start off by reading this table.
SELECT * INTO TABLE @DATA(gt_t001k) FROM t001k ORDER BY bukrs.
So far so good. Now, our goal is to build a list of unique BUKRS values. Using classical ABAP, this is possible via the COLLECT command.
TYPES: BEGIN OF t_bukrs, bukrs TYPE bukrs, END OF t_bukrs, tt_bukrs TYPE STANDARD TABLE OF t_bukrs WITH DEFAULT KEY. DATA: gs_bukrs TYPE t_bukrs, gt_bukrs TYPE tt_bukrs. LOOP AT gt_t001k ASSIGNING FIELD-SYMBOL(<gs_t001k>). gs_bukrs-bukrs = <gs_t001k>-bukrs. COLLECT gs_bukrs INTO gt_bukrs. ENDLOOP.
If we move forward to ABAP 7.40, we can achieve the same result with a better approach:
DATA(gt_bukrs) = CORRESPONDING tt_bukrs( gt_t001k ). SORT gt_bukrs BY bukrs. DELETE ADJACENT DUPLICATES FROM gt_bukrs COMPARING bukrs.
However, we can reduce the code even more by using the group command.
DATA(gt_bukrs) = VALUE tt_bukrs( FOR GROUPS gr1 OF gs_t001k IN gt_t001k GROUP BY gs_t001k-bukrs ( bukrs = gr1 ) ).
Cool eh? Just one line of code, and you are there!
Things get cooler when you want to do operations by grouping the data in an internal table. For example; you want to write the BWKEY’s corresponding to each BUKRS. Without grouping, you would first build GT_BUKRS, and then write two nested LOOPs to achieve that.
LOOP AT gt_bukrs ASSIGNING FIELD-SYMBOL(<gs_bukrs>). NEW-LINE. WRITE AT 1(5) 'Group'. WRITE AT 7(20) <gs_bukrs>-bukrs. LOOP AT gt_t001k ASSIGNING FIELD-SYMBOL(<gs_t001k>) WHERE bukrs EQ <gs_bukrs>-bukrs. NEW-LINE. WRITE <gs_t001k>-bwkey. ENDLOOP. ENDLOOP.
However; using the grouping option, you don’t even need to build GT_BUKRS. You can achieve the same goal by using GT_T001K alone.
LOOP AT gt_t001k INTO DATA(gs_line) GROUP BY ( gr_bukrs = gs_line-bukrs ) ASCENDING ASSIGNING FIELD-SYMBOL(<gs_bukrs>). NEW-LINE. WRITE AT 1(5) 'Group'. WRITE AT 7(20) <gs_bukrs>-gr_bukrs. LOOP AT GROUP <gs_bukrs> ASSIGNING FIELD-SYMBOL(<gs_sub>). NEW-LINE. WRITE: <gs_sub>-bwkey. ENDLOOP. ENDLOOP.
And voila! This technique can be used for multi level grouping as well. Check the following code sample:
SELECT ekko~ebeln, ekpo~ebelp, ekpo~matnr, eket~etenr, eket~eindt, eket~menge INTO TABLE @DATA(gt_all) FROM ekko INNER JOIN ekpo ON ekpo~ebeln EQ ekko~ebeln INNER JOIN eket ON eket~ebeln EQ ekko~ebeln AND eket~ebelp EQ ekpo~ebelp WHERE ekko~ebeln EQ '5500000026' OR ekko~ebeln EQ '5500000027'. LOOP AT gt_all INTO DATA(gs_1) GROUP BY ( ebeln = gs_1-ebeln ebelp = gs_1-ebelp ) ASCENDING ASSIGNING FIELD-SYMBOL(<gs_all>). NEW-LINE. WRITE: 'Outer loop for ', <gs_all>-ebeln, <gs_all>-ebelp. LOOP AT GROUP <gs_all> INTO DATA(gs_2) GROUP BY ( ebeln = <gs_all>-ebeln ) ASCENDING ASSIGNING FIELD-SYMBOL(<gs_sub>). NEW-LINE. WRITE: 'Inner loop for ', <gs_sub>-ebeln. ENDLOOP. ENDLOOP.
GROUP command has many further applications in internal table operations, which I might write in more detail someday. You can check Google or ABAP help for further use.
Great explanation! I'm sure it's a lot easier to code as far as key strokes.
I'm a KISS type person (Keep it simple because I'm stupid). I want to quickly be able to change my code and the code of others. If I wrote like this all the time I probably would get quicker at it. But I'm looking for something else. Faster? Stronger? More correct? Or all of the above.
I will be googling the group command because this looks so interesting. So job accomplished! You've made one person (probably a whole lot more than that) curious.
Thank you for the excellent blog!
I'm glad that I could be helpful, cheers!
I'm confused... Is SELECT DISTINCT not an option here?
And why would you use COLLECT command in the first example? DELETE ADJACENT DUPLICATES existed before 7.4.
Sorry but I feel these are just not the best examples and it takes away from your credibility as an author. Besides, this subject has already been covered in this blog back in 2014. And Horst Keller is a tough act to follow, I'm afraid.
It's nice of you to share but going forward you might want to take ABAP best practices and existing SCN content into consideration.
My purpose was to demonstrate the new commands, not write the most accurate code for go-live. In a real life situation, I wouldn't use hard coded document numbers either. Nevertheless, thanks for emphasizing the points of improvement, that's one of the reasons why tech communities are good.