Hands On: Dynamic construction of a data table to be displayed in an ALV-Grid
Introduction
The following code snippet shows an exemplary implementation how to dynamically built up a table whereas a single entry in that table contains data from different DB-tables. Despite coding the whole stuff about field catalog etc. on your own, this implementation keeps the relation to the DDIC and the only decisions to be made is about which data should be shown in the ALV-grid.
The implementation is structured as follows:
- Data is selected (for this example data from the context of tables but000, but020, adrc and adcp is used).
- The table which is meant to contain all data for the ALV-grid is built. Here, relevant components need to be specified.
- The table is filled with data. For this example we would like to get following output: For each Business Partner we would like to show all addresses as well as all person-related addresses for each address.
- The ALV-grid is created via a factory method and displayed.
Code Snippet(s)
TABLES: but000. DATA: lt_but000 TYPE STANDARD TABLE OF but000, ls_but000 TYPE but000, lt_but020 TYPE STANDARD TABLE OF but020, ls_but020 TYPE but020, lt_adrc TYPE STANDARD TABLE OF adrc, ls_adrc TYPE adrc, lt_adcp TYPE STANDARD TABLE OF adcp, ls_adcp TYPE adcp, lt_addr_no_range TYPE RANGE OF ad_addrnum, ls_addr_no_range LIKE LINE OF lt_addr_no_range. SELECT-OPTIONS: s_pno FOR but000-partner. * Select the corresponding partners. SELECT * FROM but000 INTO TABLE lt_but000 WHERE partner IN s_pno. * Check if there were any partners found. IF lt_but000 IS INITIAL. return. ENDIF. * Select address numbers for these partners. SELECT * FROM but020 INTO TABLE lt_but020 WHERE partner IN s_pno. * Built-up an address number range. LOOP AT lt_but020 INTO ls_but020. ls_addr_no_range-sign = 'I'. ls_addr_no_range-option = 'EQ'. ls_addr_no_range-low = ls_but020-addrnumber. APPEND ls_addr_no_range TO lt_addr_no_range. ENDLOOP. IF lt_addr_no_range IS NOT INITIAL. * Select the addresses. SELECT * FROM adrc INTO TABLE lt_adrc WHERE addrnumber IN lt_addr_no_range. * Select the person/address assignments. SELECT * FROM adcp INTO TABLE lt_adcp WHERE addrnumber IN lt_addr_no_range. ENDIF. * So far we got all data. * Now we will built-up a corresponding table. DATA: lr_struc_descr TYPE REF TO cl_abap_structdescr, "RTTS for structures lr_table_descr TYPE REF TO cl_abap_tabledescr, "RTTS for tables lt_components TYPE cl_abap_structdescr=>component_table, "Temp. table of component RTTI descriptions lt_table_of_components TYPE cl_abap_structdescr=>component_table, "Table of component RTTI descriptions lx_error TYPE REF TO cx_root, "Error object lr_data_ref TYPE REF TO data, "Reference to a component RTTI description lr_table_ref TYPE REF TO data. "Reference to the table of component RTTI descriptions FIELD-SYMBOLS: <fs_merge> TYPE any, <dyntable> TYPE table. * Get fields of but000. lr_struc_descr ?= cl_abap_structdescr=>describe_by_data( ls_but000 ). lt_components = lr_struc_descr->get_components( ). CLEAR lr_struc_descr. * Delete non-relevant fields. DELETE lt_components WHERE name NE 'PARTNER' AND name NE 'TYPE'. APPEND LINES OF lt_components TO lt_table_of_components. * Get fields of but020. lr_struc_descr ?= cl_abap_structdescr=>describe_by_data( ls_but020 ). lt_components = lr_struc_descr->get_components( ). CLEAR lr_struc_descr. * Delete non-relevant fields. DELETE lt_components WHERE name NE 'ADDRNUMBER' AND name NE 'XDFADR'. APPEND LINES OF lt_components TO lt_table_of_components. * Get fields of adrc. lr_struc_descr ?= cl_abap_structdescr=>describe_by_data( ls_adrc ). lt_components = lr_struc_descr->get_components( ). CLEAR lr_struc_descr. * Delete non-relevant fields. DELETE lt_components WHERE name NE 'STREET' AND name NE 'HOUSE_NUM1' AND name NE 'POST_CODE1' AND name NE 'CITY1'. APPEND LINES OF lt_components TO lt_table_of_components. * Get fields of adcp. lr_struc_descr ?= cl_abap_structdescr=>describe_by_data( ls_adcp ). lt_components = lr_struc_descr->get_components( ). CLEAR lr_struc_descr. * Delete non-relevant fields. DELETE lt_components WHERE name NE 'PERSNUMBER' AND name NE 'COMP_PERS'. APPEND LINES OF lt_components TO lt_table_of_components. * Create a RTTS instance for the merged structure. TRY. lr_struc_descr = cl_abap_structdescr=>create( p_components = lt_table_of_components ). CATCH cx_sy_struct_creation INTO lx_error. ENDTRY. CREATE DATA lr_data_ref TYPE HANDLE lr_struc_descr. "Create data ref. variable ASSIGN lr_data_ref->* TO <fs_merge>. "Dereference the data reference * Create a RTTS instance for a table of the merged structure. TRY. lr_table_descr = cl_abap_tabledescr=>create( p_line_type = lr_struc_descr ). CATCH cx_sy_table_creation INTO lx_error. ENDTRY. CREATE DATA lr_table_ref TYPE HANDLE lr_table_descr. "Create data ref. variable ASSIGN lr_table_ref->* TO <dyntable>. "Dereference the data reference * Now we have a corresponding line structure and table to work with. * It contains components for all field we'd specified. * Fill the table... * Loop at all partners. LOOP AT lt_but000 INTO ls_but000. * Loop at all addresses of the current partner. LOOP AT lt_but020 INTO ls_but020 WHERE partner = ls_but000-partner. MOVE-CORRESPONDING ls_but020 TO <fs_merge>. * Loop at address entries. LOOP AT lt_adrc INTO ls_adrc WHERE addrnumber = ls_but020-addrnumber. MOVE-CORRESPONDING ls_adrc TO <fs_merge>. LOOP AT lt_adcp INTO ls_adcp WHERE addrnumber = ls_but020-addrnumber. MOVE-CORRESPONDING ls_adcp TO <fs_merge>. APPEND <fs_merge> TO <dyntable>. ENDLOOP. IF sy-subrc EQ 4. APPEND <fs_merge> TO <dyntable>. ENDIF. ENDLOOP. IF sy-subrc EQ 4. APPEND <fs_merge> TO <dyntable>. ENDIF. ENDLOOP. ENDLOOP. * The table is filled. For this Hands On we just * would like to present the data in a Popup containing * a corresponding ALV-grid. DATA lo_alv TYPE REF TO cl_salv_table. * Create an ALV-grid. TRY. cl_salv_table=>factory( IMPORTING r_salv_table = lo_alv CHANGING t_table = <dyntable> ). CATCH cx_salv_msg INTO lx_error. ENDTRY. * Enable some functions. DATA: lr_functions TYPE REF TO cl_salv_functions_list. lr_functions = lo_alv->get_functions( ). lr_functions->set_all( abap_true ). IF lo_alv IS BOUND. * Set display properties. lo_alv->set_screen_popup( start_column = 25 "i_start_column end_column = 275 "i_end_column start_line = 2 "i_start_line end_line = 45 "i_end_line ). * Show the result. lo_alv->display( ). ENDIF.
Explanation
In a first step the data is selected. For this example we will work with Business Partners and its addresses. Thus, we choose tables
- BUT000 (Business Partner central table)
- BUT020 (Relation between Business Partner and its address(es); one partner might have 0..* addresses)
- ADRC (Address central table)
- ADCP (Address for person).
The relations and cardinalities are as follows (never mind if they are different in reality):
The second step is the construction of a dynamic structure whereas the components of the structure do have the same specification as the ones we would like to display in the ALV-grid. Imporant is that we don not want to provide all the meta information about that component but just “keep” the connection to the DDIC. For each table the approach is the same:
- Via RTTS we gather a structure description.
- The description does provide information about each component of the structure.
- We keep only those components that are needed later on in the ALV-grid.
- Save these component information for later use.
Afterwards, all gather components or rather component information is used in order to create a new structure description via RTTS. This time, this structure description is for a structure that consists of exactly the components we kept. Using this structure description we assign a field-symbol that is of that structure type. Furthermore using this structure description a table description is created and a field-symbol is assigned using it. As result there are a dynamic structure and table.
The third step is just about filling the dynamic table. Therefore the dynamic structure is filled correspondingly from each data set of the mentioned tables. Last but not least an ALV-grid in created and shown.
Availability
Key | Value |
---|---|
Software Component | SAP_BASIS |
Requires Client-Side Software Library | No |
Code Snippet is OS dependent | No |