Internal table의 collect 또는 At-New 등의 기능을 대신 사용하면 좋을것 같음.
잘 사용하면 performance 에 좋을것 같음.



You know the GROUP BY clause from SQL. There was not such a clause for internal tables up to now. 

All we had was that clumsy group level processing with statements AT NEW … that relied on the order of table columns and contents that is sorted respectively.

With release 7.40, SP08 there is a real GROUP BY clause for LOOP AT itab that is much more powerful than the SQL one.


DATA flights TYPE TABLE OF spfli WITH EMPTY KEY.

SELECT * FROM  spfli
         WHERE carrid = ‘…’
         INTO TABLE @flights.

DATA members LIKE flights.
LOOP AT flights INTO DATA(flight)
     GROUP BY ( carrier = flight-carrid cityfr = flight-cityfrom )
              ASCENDING
              ASSIGNING FIELD-SYMBOL(<group>).
  CLEAR members.
  LOOP AT GROUP <group> ASSIGNING FIELD-SYMBOL(<flight>).
    members = VALUE #( BASE members ( <flight> ) ).
  ENDLOOP.
  cl_demo_output=>write( members ).
ENDLOOP.
cl_demo_output=>display( ).


Looks like dreaded nested LOOPs, but it isn’t quite that – no quadratic behavior!  What happens here is that the first LOOP statement is executed over all internal table lines in one go and the new GROUP BY addition groups the lines. Technically, the lines are bound internally  to a group that belongs to a group key that is specified behind GROUP BY.The group key is calculated for each loop pass. And the best is, it need not be as simple as using only column values, but you can use any expressions here that normally depend on the contents of the current line, e.g. comparisons, method calls, …. The LOOP body is not evaluated in this phase!


Only after the grouping phase, the LOOP body is evaluated. Now a second (but not nested) loop is carried out over the groups constructed in the first phase. Inside this group loop you can access the group using e.g. the field symbol <group> that is assigned to the group in the above example. If you want to access the members of the group, you can us the new LOOP AT GROUP statement, which enables a member loop within the group loop. In the example, the members are inserted into a membertable and displayed.

Here another example, where the group key is evaluated from method calls:


LOOP AT flights INTO DATA(wa)

     GROUP BY ( tz_from = get_time_zone( wa-airpfrom )

                tz_to   = get_time_zone( wa-airpto ) )

     ASSIGNING FIELD-SYMBOL(<group>).

  …

ENDLOOP.


Of course, there is also expression enabled syntax for grouping internal tables.

In a first step, we get rid of LOOP AT GROUP by replacing it with a FOR expression:


DATA members LIKE flights.

LOOP AT flights INTO DATA(flight)

     GROUP BY ( carrier = flight-carrid cityfr = flight-cityfrom )

              ASCENDING

              ASSIGNING FIELD-SYMBOL(<group>).

  members = VALUE #( FOR m IN GROUP <group> ( m ) ).

  cl_demo_output=>write( members ).

ENDLOOP.

cl_demo_output=>display( ).


The IN GROUP is a new addition to FOR. Second, away with the outer LOOP:


TYPES t_flights LIKE flights.

DATA out TYPE REF TO if_demo_output.

out = REDUCE #( INIT o = cl_demo_output=>new( )

                FOR GROUPS <group> OF flight IN flights

                GROUP BY ( carrier = flight-carrid cityfr = flight-cityfrom )

                  ASCENDING

                LET members = VALUE t_flights( FOR m IN GROUP <group> ( m ) ) IN

                NEXT o = o->write( members ) ).

out->display( ).


FOR GROUPS is another new FOR variant. Believe me, it does the same as the variants above. But for reasons of readability, the combination of LOOP AT GROUP with a FOR IN GROUP within might be the preferable one, at least for this example 😈 .

For a deep dive, read this and this!

PS: If you are confused what kind of loops and nesting takes place, have a look at my comment below.

PPS: For a step-by-step approach to GROUP BY see GROUP BY for Internal Tables – Step by Step


2. https://blogs.sap.com/2016/06/23/group-by-for-internal-tables-step-by-stepc/

In my blog  ABAP News for 7.40, SP08 – GROUP BY for Interna… | SCN I introduced the GROUP BYaddition for LOOP AT for internal tables.


Since there seems to be some confusion about the syntax and its meaning, let us approach the grouping of internal tables step by step using a very simple case and you will see that it isn’t that complicated at all. 

I also attached the full text of a program, that executes the following steps and produces some output.

Say, you have an internal table spfli_tab TYPE TABLE OF spfli  filled with data from database table SPFLI (what else …).

Step 1, Grouping by one column

The most simple thing you can do is grouping by one column:

LOOP AT spfli_tab INTO wa

                  GROUP BY wacarrid.

       … wacarrid ...

ENDLOOP.


Inside the loop you can access wa, especially wa-carridwa contains the first line of each group that is created by GROUP BY. This is called representative binding. Inside the loop wa represents a group.


In order to access the members of each group, you add a member loop:


LOOP AT spfli_tab INTO wa

                  GROUP BY wa-carrid.

  …

  LOOP AT GROUP wa INTO DATA(member).

    … member-… …

  ENDLOOP.

  …

ENDLOOP.


member is a structure with the line type of spfli_tab and contains the members of each group.


Step 2, Grouping by more than one column


If you want to group by more than one grouping criterion (columns in the most simple case), you write:


LOOP AT spfli_tab INTO wa

                  GROUP BY ( key1 = wa-carrid key2 = wa-airpfrom ).

  … wa-carrid … wa-airpfrom …

ENDLOOP.


In this case, you construct a structured group key. In the case of representative binding shown here, wa is reused for accessing the group key inside the loop.


In order to access the members of the groups, you can add exactly the same member loop as in step 1 above.


Step 3, Group key binding for grouping by one column


Besides the representative binding, where the INTO-clause of LOOP AT is reused for accessing the group, you can define a group key binding:


LOOP AT spfli_tab INTO wa

                  GROUP BY wa-carrid

                  INTO DATA(key).

  … key …

ENDLOOP.


Not too different from step 1 above, eh? Instead of reusing wa, you use an elementary data object key that for convenience is declared inline here. Group key binding offers some more functionality compared to representative binding (additions WITHOUT MEMBERSGROUP SIZEGROUP INDEX). If you don’t need those, you can stay with representative binding. Nevertheless, I myself always prefer group key binding, since it makes the group key more explicit. But that’s a question of taste.


Inserting the member loop works as before:


LOOP AT spfli_tab INTO wa

                  GROUP BY WA-CARRID

                  INTO DATA(key).

  …

  LOOP AT GROUP key INTO member.

    … members …

  ENDLOOP.

  …

ENDLOOP.


Note, that you access the group using the name key now.


Step 4, Group key binding for grouping by more than one column


Last but not least, group key binding for structured group keys:


LOOP AT spfli_tab INTO wa

                  GROUP BY ( key1 = wa-carrid key2 = wa-airpfrom )

                  INTO DATA(key).

  … key-key1 … key-key2 …

ENDLOOP.


Now, key is a structure with the components key1 and key2. The member loop can be added exactly as in step 3.


If you aren’t interested in the members, you can use the NO MEMBERS addition in order to save some run time and some memory. E.g.


LOOP AT spfli_tab INTO wa

                  GROUP BY ( key1 = wa-carrid key2 = wa-airpfrom

                             index = GROUP INDEX size = GROUP SIZE )

                  WITHOUT MEMBERS

                  INTO DATA(key).

  … key-key1 … key-key2 … key-index … key-size … 

ENDLOOP.


A member loop is not possible here. But key is enriched with some predefiined optional components for additional informations. 


Conclusion


Not too complicated, or?


Having understood these simple facts, you can go on, read the documentation, and do more complicated things, e.g. exploiting the fact that you can use expressions for the RHS of the group key definitions or using FOR expressions instead of LOOP AT.


설정

트랙백

댓글