Reputation: 611
In an ITAB I have 3 fields: ACCOUNT-OBJECT_AMOUNT and a sample is:
64000 KAGR1 10
64000 KAGR1 15
64010 KAGR1 20
64010 KAGR2 15
64020 KAGR2 10
64020 KAGR2 10
And I want the display to be like the below:
KAGR1 KAGR2
64000 25
64010 20 15
64020 30
Can anyone know how to display it in an ALV?
Thanks
Upvotes: 0
Views: 1016
Reputation: 2565
Here is a generic solution. Note that the method show_table_grouped_by
has no knowledge of the type of the table, so it can be used with any table, although I bet there are some field types that would break the dynamic code. The data to display can have multiple fields that will be used as keys (your example only has one) and one field that is used for the columns (i_group_by
) and one field that is used to aggregate from (i_aggregate_from
). Most of the idea of this program comes from this blog, however the solution below is more dynamic. The complete program processes the data as provided in the question, with the value in the last line corrected to come to the result in the example.
If you know that the values for your group by field will be limited to a certain number of values you can make a less dynamic solution that will probably be more efficient.
REPORT zso_group_alv.
TYPES: BEGIN OF ts_data,
field1 TYPE char10,
group TYPE char10,
val TYPE i,
END OF ts_data,
tt_data TYPE STANDARD TABLE OF ts_data.
DATA: gt_data TYPE tt_data.
CLASS lcl_alv_grouped DEFINITION.
PUBLIC SECTION.
CLASS-METHODS:
show_table_grouped_by IMPORTING VALUE(it_data) TYPE ANY TABLE
i_group_by TYPE fieldname
i_aggregate_from TYPE fieldname,
group_fld_name IMPORTING i_value TYPE any
RETURNING VALUE(fld_name) TYPE fieldname.
ENDCLASS.
CLASS lcl_alv_grouped IMPLEMENTATION.
METHOD group_fld_name.
" Returns the field name for the group fields
" This is to make sure there are no reserved names used or
" reuse of already existing fields
fld_name = 'fld_' && i_value.
ENDMETHOD.
METHOD show_table_grouped_by.
" Shows the data in table IT_DATA in an ALV
" The data is transposed
" The data from field I_AGGREGATE_FROM is summed into groups
" from the values in the field I_GROUP_BY
" All the other fields in the table are treated as the key
" fields for the transposed table
DATA: ls_component TYPE cl_abap_structdescr=>component,
lt_components TYPE cl_abap_structdescr=>component_table,
lr_struct TYPE REF TO cl_abap_structdescr,
lt_keys TYPE abap_sortorder_tab,
lt_key_components TYPE cl_abap_structdescr=>component_table,
"ls_keys TYPE REF TO data,
lr_trans_table TYPE REF TO data,
lr_trans_wa TYPE REF TO data,
lr_keys_type TYPE REF TO cl_abap_structdescr,
ls_keys TYPE REF TO data,
ls_keys_prev TYPE REF TO data,
lr_salv TYPE REF TO cl_salv_table.
FIELD-SYMBOLS: <trans_table> TYPE STANDARD TABLE.
" Determine the fields in the transposed table
LOOP AT it_data ASSIGNING FIELD-SYMBOL(<data>).
AT FIRST.
" Get field to aggregate
ASSIGN COMPONENT i_aggregate_from OF STRUCTURE <data> TO FIELD-SYMBOL(<aggregate_field>).
IF sy-subrc NE 0.
RETURN. " Would be nice to tell the calling program about this error
ENDIF.
" Gather all the other fields from the data table, these are treated as keys
lr_struct ?= cl_abap_datadescr=>describe_by_data( <data> ).
LOOP AT lr_struct->get_components( ) ASSIGNING FIELD-SYMBOL(<component>).
IF <component>-name NE i_aggregate_from AND
<component>-name NE i_group_by.
APPEND <component> TO: lt_components,
lt_key_components.
APPEND VALUE #( name = <component>-name
descending = abap_false
astext = abap_true
) TO lt_keys.
ENDIF.
ENDLOOP.
ENDAT. " FIRST
" Get the group by field
ASSIGN COMPONENT i_group_by OF STRUCTURE <data> TO FIELD-SYMBOL(<group_field>).
IF sy-subrc NE 0.
RETURN. " Would be nice to tell the calling program about this error
ENDIF.
" Gather all the values in the group by field
DATA(l_new_group) = group_fld_name( <group_field> ).
READ TABLE lt_components WITH KEY name = l_new_group TRANSPORTING NO FIELDS.
IF sy-subrc NE 0.
ls_component-name = l_new_group.
ls_component-type ?= cl_abap_datadescr=>describe_by_data( <aggregate_field> ).
APPEND ls_component TO lt_components.
ENDIF.
ENDLOOP. " IT_DATA
" LT_COMPONENTS is now filled with all the fields to show in the ALV
" Create the transpose table and fill its
DATA(lr_trans_table_type) = cl_abap_tabledescr=>create( cl_abap_structdescr=>create( lt_components ) ).
CREATE DATA lr_trans_table TYPE HANDLE lr_trans_table_type.
ASSIGN lr_trans_table->* TO <trans_table>.
" Data needs to be sorted to generate the rows in the transposed table
SORT it_data BY (lt_keys).
" Create structures to keep track of the key values
lr_keys_type ?= cl_abap_structdescr=>create( lt_key_components ).
CREATE DATA ls_keys TYPE HANDLE lr_keys_type.
CREATE DATA ls_keys_prev TYPE HANDLE lr_keys_type.
ASSIGN ls_keys->* TO FIELD-SYMBOL(<keys>).
ASSIGN ls_keys_prev->* TO FIELD-SYMBOL(<keys_prev>).
" Transpose the data
LOOP AT it_data ASSIGNING <data>.
MOVE-CORRESPONDING <data> TO <keys>.
IF <keys> NE <keys_prev>.
" Found a new key combination, add a row to the transposed table
APPEND INITIAL LINE TO <trans_table> ASSIGNING FIELD-SYMBOL(<trans_data>).
MOVE-CORRESPONDING <data> TO <trans_data>. " Filling the key fields
ENDIF.
" Agragate the value into the right group
ASSIGN COMPONENT i_aggregate_from OF STRUCTURE <data> TO FIELD-SYMBOL(<value>).
ASSIGN COMPONENT i_group_by OF STRUCTURE <data> TO FIELD-SYMBOL(<group>).
ASSIGN COMPONENT group_fld_name( <group> ) OF STRUCTURE <trans_data> TO FIELD-SYMBOL(<trans_value>).
ADD <value> TO <trans_value>.
" Remember keys to compare with the next row
<keys_prev> = <keys>.
ENDLOOP. " IT_DATA
" Display transposed data in ALV
TRY.
cl_salv_table=>factory(
* EXPORTING
* list_display = IF_SALV_C_BOOL_SAP=>FALSE " ALV Displayed in List Mode
* r_container = " Abstract Container for GUI Controls
* container_name =
IMPORTING
r_salv_table = lr_salv " Basis Class Simple ALV Tables
CHANGING
t_table = <trans_table>
).
CATCH cx_salv_msg. "
" Some error handling would be nice
ENDTRY.
" Will need to do something about the column headers
lr_salv->display( ).
ENDMETHOD.
ENDCLASS.
START-OF-SELECTION.
APPEND VALUE #( field1 = '64000' group = 'KAGR1' val = 10 ) TO gt_data.
APPEND VALUE #( field1 = '64000' group = 'KAGR1' val = 15 ) TO gt_data.
APPEND VALUE #( field1 = '64010' group = 'KAGR1' val = 20 ) TO gt_data.
APPEND VALUE #( field1 = '64010' group = 'KAGR2' val = 15 ) TO gt_data.
APPEND VALUE #( field1 = '64020' group = 'KAGR2' val = 10 ) TO gt_data.
APPEND VALUE #( field1 = '64020' group = 'KAGR2' val = 20 ) TO gt_data.
lcl_alv_grouped=>show_table_grouped_by(
EXPORTING
it_data = gt_data
i_group_by = 'GROUP'
i_aggregate_from = 'VAL'
).
Upvotes: 4