Hi at all! I am relatively new to ABAP and I am just sitting in on creating some templates for often used topics.
The problem I have is that a lot of posts are not explained very well, hence it is often hard to understand what the person who blogged something about a topic is really doing within the code. Therefore I provide now – in my eyes – an important topic regarding the creation of internal tables at runtime.This gives you more flexibility and this class can also be reused.
I try to describe this topic as clear as possible to you.
Moreover i have decided to not use the plain text editor because this is pretty impractical reagarding copying.
If you have any questions or suggestions please let me now!!!
There is also a picture of the report attached
Regards Patrick.
Below you can see the class zcl_dynamic_db_query which handles the dynamic creation of an internal table.
CLASS zcl_dynamic_db_query DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
* public static method 'main' receives 3 input parameters from the calling program ->
* the name of the DB-Table, the Columns which are needed and the where clause
CLASS-METHODS main
IMPORTING
!dbtab TYPE csequence
!cols TYPE csequence
!where TYPE csequence.
PROTECTED SECTION.
PRIVATE SECTION.
* private static method 'display'; is used to give out the table header and
* the result of the SELECT Statement executed in static method 'main'
CLASS-METHODS display
IMPORTING
VALUE(result) TYPE STANDARD TABLE
!struct_header TYPE REF TO cl_abap_structdescr .
ENDCLASS. "end of definition
CLASS zcl_dynamic_db_query IMPLEMENTATION.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_DYNAMIC_DB_QUERY=>MAIN
* +-------------------------------------------------------------------------------------------------+
* | [--->] DBTAB TYPE CSEQUENCE
* | [--->] COLS TYPE CSEQUENCE
* | [--->] WHERE TYPE CSEQUENCE
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD main.
* here we make use of the ABAP RTTS (Run Time Type Services) and
* RTTI (Run Time Type Information) Classes which help us to find out
* the structure of a table at runtime and also the types of its columns
DATA: type_descr TYPE REF TO cl_abap_typedescr,
struct_descr TYPE REF TO cl_abap_structdescr,
table_descr TYPE REF TO cl_abap_tabledescr,
table_ref TYPE REF TO data,
components TYPE cl_abap_structdescr=>component_table,
component LIKE LINE OF components,
error TYPE REF TO cx_root.
* field symbols are place holder for existing data objects and parts of existing data objects.
* we need them to create the table to fill in the input of the query
FIELD-SYMBOLS: <table> TYPE ANY TABLE.
* this creates a bunch of type descriptions of the table 'dbtab' and
* saves the typeinformation into the variable 'type_descr'
cl_abap_typedescr=>describe_by_name(
EXPORTING p_name = dbtab
RECEIVING p_descr_ref = type_descr
EXCEPTIONS type_not_found = 4 ).
IF sy-subrc = 4.
MESSAGE 'Type not found error' TYPE 'I' DISPLAY LIKE 'E'.
RETURN.
ENDIF.
TRY.
* now we use a down cast. the downcast is used when the static type of the
* source variable is 'data' and the static type of the target variable
* is completely typed. if not the exception cx_sy_move_cast_error is raised
struct_descr ?= type_descr.
CATCH cx_sy_move_cast_error INTO error.
MESSAGE error TYPE 'I' DISPLAY LIKE 'E'.
RETURN.
ENDTRY.
* get components saves all components(== columns) of the table into the variable 'components'
components = struct_descr->get_components( ).
* If all columns are selected all components of the structure remain in the components variable
IF cols = '*'.
* else sort out those who are not needed
ELSE.
LOOP AT components INTO component.
CONCATENATE '\b' component-name '\b' INTO component-name.
* search for all components which are inside of 'cols' and sort
* out those columns inside the' components ' variable which are not needed
FIND REGEX component-name IN cols.
IF sy-subrc <> 0.
DELETE components INDEX sy-tabix.
ENDIF.
ENDLOOP.
ENDIF.
TRY.
* now we overwrite the existing structure with a new structure which
* holds only those columns which are needed
struct_descr = cl_abap_structdescr=>create( components ).
* now we 'create' the description of the table which will be needed in the end
table_descr = cl_abap_tabledescr=>create( struct_descr ).
CATCH cx_sy_struct_creation cx_sy_table_creation INTO error.
MESSAGE error TYPE 'I' DISPLAY LIKE 'E'.
RETURN.
ENDTRY.
TRY.
* with 'TYPE HANDLE' we are able to reference a typed object of RTTS
* the information was gathered with the aid of RTTI and now
* the information is saved into the variable table_ref. This is necessary
* because we cannot assign with a RTTS object --> we need a data variable to do so
CREATE DATA table_ref TYPE HANDLE table_descr.
* now assign the structure of the table to the field symbol
ASSIGN table_ref->* TO <table>.
CATCH cx_sy_create_data_error INTO error.
MESSAGE error TYPE 'I' DISPLAY LIKE 'E'.
RETURN.
ENDTRY.
* now we have to query the needed data from the table and save it into our table
TRY.
SELECT (cols)
FROM (dbtab)
INTO CORRESPONDING FIELDS OF TABLE <table>
WHERE (where).
CATCH cx_sy_sql_error INTO error.
MESSAGE error TYPE 'I' DISPLAY LIKE 'E'.
RETURN.
ENDTRY.
* now we call the display function exporting the table with our information
* and the structure of the table (which is needed for the header line)
display(
EXPORTING result = <table>
struct_header = struct_descr
).
ENDMETHOD. "main
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Private Method ZCL_DYNAMIC_DB_QUERY=>DISPLAY
* +------------------------------------ -------------------------------------------------------------+
* | [--->] RESULT TYPE STANDARD TABLE
* | [--->] STRUCT_HEADER TYPE REF TO CL_ABAP_STRUCTDESCR
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD display.
FIELD-SYMBOLS: <wa> TYPE any,
<component> TYPE any,
<wa_header> LIKE LINE OF struct_header->components.
* reading and displaying the header of the dynamically created table
LOOP AT struct_header->components ASSIGNING <wa_header>.
WRITE <wa_header>-name.
ENDLOOP.
* reading out the content of the internal table
NEW-LINE.
LOOP AT result ASSIGNING <wa>.
DO.
ASSIGN COMPONENT sy-index OF STRUCTURE <wa>
TO <component>.
IF sy-subrc <> 0.
EXIT. "no more components
ENDIF.
WRITE: <component>.
ENDDO.
NEW-LINE.
ENDLOOP.
ENDMETHOD. " end of method 'display'
ENDCLASS. "end of class implementation
Now the report with a call of the class.
*&---------------------------------------------------------------------*
*& Report ZLP_DYN_DB
*&
*&---------------------------------------------------------------------*
*&
*&
*&---------------------------------------------------------------------*
REPORT ZLP_DYN_DB.
parameters:
p_dbtab Type c length 132,
p_cols Type c length 132,
p_where Type c length 132.
START-OF-SELECTION.
zcl_dynamic_db_query=>main(
EXPORTING dbtab = p_dbtab
cols = p_cols
where = p_where ).