ABAP Internal Table Group Operations

1464-ppt

Today, we will be inspecting some cool grouping techniques introduced in ABAP 7.40.

Unique values of single field

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!

Unique values of multiple fields

In case you want to build a summary table using multiple fields, here is a helpful sample code:

DATA: BEGIN OF lt_sum OCCURS 0,
        fcurr TYPE tcurr-fcurr,
        tcurr TYPE tcurr-tcurr,
      END OF lt_sum.

SELECT * FROM tcurr INTO TABLE @DATA(lt_curr).

lt_sum[] = VALUE ( FOR GROUPS _gr1 OF _curr IN lt_curr
                   GROUP BY ( key1 = _curr-fcurr 
                              key2 = _curr-tcurr )
                   ( fcurr = _gr1-key1
                     tcurr = _gr1-key2 ) ).

Grouping entries

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.

Summing Values

Here is an example ABAP code which works like a SELECT SUM command in the internal table.

TYPES: BEGIN OF mard_sum1,
         matnr TYPE mard-matnr,
         werks TYPE mard-werks,
         labst TYPE mard-labst,
       END OF mard_sum1,

       mard_sum1s TYPE HASHED TABLE OF mard_sum1
                  WITH UNIQUE KEY primary_key COMPONENTS matnr werks.

TYPES: BEGIN OF mard_sum2,
         matnr TYPE mard-matnr,
         labst TYPE mard-labst,
       END OF mard_sum2,

       mard_sum2s TYPE HASHED TABLE OF mard_sum2
                  WITH UNIQUE KEY primary_key COMPONENTS matnr.

SELECT matnr, werks, lgort, labst FROM mard INTO TABLE @DATA(mard_entries).

DATA(sum1) = REDUCE mard_sum1s(
    INIT _sum = VALUE mard_sum1s( )
    FOR GROUPS _grp OF _mard_entry IN mard_entries
    GROUP BY ( matnr = _mard_entry-matnr
               werks = _mard_entry-werks )
    NEXT _sum = VALUE mard_sum1s(
         BASE _sum
         ( matnr = _grp-matnr
           werks = _grp-werks
           labst = REDUCE #(
                INIT _labst_sum TYPE mard-labst
                FOR _grp_entry IN GROUP _grp
                NEXT _labst_sum = _labst_sum + _grp_entry-labst ) ) ) ).

Verdict

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.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s