Skip to content

ABAP Keyword Documentation →  ABAP - Reference →  Processing External Data →  ABAP Database Accesses →  Open SQL →  Open SQL - Read Accesses →  SELECT →  SELECT - Examples 

SELECT, Dynamic Token Specification

The example demonstrates dynamic token specification in OpenSQL for the statement SELECT.

Other versions: 7.31 | 7.40 | 7.54

Source Code


    TYPES whitelist     TYPE HASHED TABLE OF string
                             WITH UNIQUE KEY table_line.

    DATA: right    TYPE tabname VALUE 'SPFLI',
          select   TYPE TABLE OF edpline,
          sublist  TYPE edpline,
          from     TYPE string,
          first_on TYPE abap_bool VALUE abap_true,
          tref     TYPE REF TO data.


      EXPORTING text  = `Right Table of Join`
      CHANGING  field = right ).

    DATA(whitelist) =  VALUE whitelist( ( `SPFLI` )
                                       ( `SCARR` )
                                       ( `SAPLANE` ) ).

        right = cl_abap_dyn_prg=>check_whitelist_tab(
                  val = to_upper( right )
                  whitelist = whitelist ).
      CATCH cx_abap_not_in_whitelist.
          `Only the following tables are allowed:` ).
        cl_demo_output=>display( whitelist ).

    first_on = abap_true.
    CLEAR select.
    CLEAR sublist.
    CLEAR from.

    DATA(comp_tab1) =
      CAST cl_abap_structdescr( cl_abap_typedescr=>describe_by_name(
                                 left ) )->get_components( ).
    DATA(comp_tab2) =
      CAST cl_abap_structdescr( cl_abap_typedescr=>describe_by_name(
                                 right ) )->get_components( ).

    DELETE comp_tab1 WHERE name = 'MANDT'.
    DELETE comp_tab2 WHERE name = 'MANDT'.

    from = left && ` join ` && right && ` on `.

    LOOP AT comp_tab1 INTO DATA(comp1) WHERE name IS NOT INITIAL.
      sublist = left && '~' && comp1-name && ','.
      APPEND sublist TO select.

    LOOP AT comp_tab2 INTO DATA(comp2) WHERE name IS NOT INITIAL.
          comp1 = comp_tab1[ KEY primary_key name = comp2-name ].
          IF first_on = abap_false.
            from = from && ` and `.
            first_on = abap_false.
          from = from && left  && `~` && comp2-name &&
                ` = ` && right && `~` && comp2-name.
        CATCH cx_sy_itab_line_not_found.
          APPEND comp2 TO comp_tab1.
          sublist = right && '~' && comp2-name && ','.
          APPEND sublist TO select.

    DATA(struct_type) = cl_abap_structdescr=>create( comp_tab1 ).
    DATA(table_type) = cl_abap_tabledescr=>create( struct_type ).
    CREATE DATA tref TYPE HANDLE table_type.
    ASSIGN tref->* TO <itab>.

    ASSIGN select[ lines( select ) ] TO FIELD-SYMBOL(<comp>).
    REPLACE `,` IN <comp>  WITH ``.
        SELECT (select) FROM (from) INTO TABLE @<itab>.
        cl_demo_output=>display( <itab> ).
      CATCH cx_sy_dynamic_osql_syntax
            cx_sy_dynamic_osql_semantics INTO DATA(exc).
        cl_demo_output=>display( exc->get_text( ) ).


Once the program has started, the name of one of the database tables SPFLI, SCARR, or SAPLANE can be entered. The table entered is then associated with the table SFLIGHT in accordance with its foreign key relationship. This assumes that all fields with the same name have a foreign key relationship with each other.

The selected table name is assigned to the field right. The RTTS class CL_ABAP_TYPEDESCR is used to determine the type description for the columns in the left and right table of the join. The method GET_COMPONENTS is used to store these in two type description tables comp_tab1 or comp_tab2, which contain an entry for each column of the database table in question.

Then, a fragment of the FROM clause is created, which contains the names of the tables to be joined; the FROM clause is later completed using the ON conditions.

All columns of the left table should be entered in the SELECT list, as well as those columns of the right table for which no columns with the same name exist in the left table. The content of the type description tables is processed in loops.

Initially, the columns of the left table are processed. The current column is incorporated first into the dynamic SELECT list, which should be specified in the internal table select. The column name comp1-name is prefixed with the table name in left, to ensure its uniqueness. The statement MOVE-CORRESPONDING is used to copy the column description from comp_tab1 to an internal table comp_tab_join whose type is suitable for creating the objects later.

The columns of the right table are searched in the left table. If the column comp2-name only exists in the right table, it is, for the time being, incorporated into the type description table comp_tab_join. After that, it is added to all columns of the left table of the SELECT list select, just like before.

If the column in comp2-name exists in both tables, an ON condition that compares columns with the same name from the left and the right table, is added to the dynamic FROM clause from.

The type description table comp_tab_join and the static method CREATE of the class CL_ABAP_STRUCTDESCR can now be used to create a matching type description object for the structure of the target area of the statement SELECT. This type description object could now be specified after the addition TYPE HANDLE of the statement CREATE DATA to create a structured work area. However, we go one step further and use the method CREATE of the class CL_ABAP_TABLEDESCR to create a type description object for an internal table of this row type and create this with CREATE DATA. By assigning the dynamically created internal tables to a field symbol <itab>, we create a name for the internal table that is useable in the INTO clause of the statement SELECT. Direct specification of a dereferencing tref->* in statements other than ASSIGN is only possible if tref is not generically typed. However, in our example, tref is generically typed with TYPE REF TO data.

Subsequently, the data is read with a fully dynamic statement SELECT. The content of the internal table <itab> is produced.

Security Note

If used wrongly, dynamic programming techniques can present a serious security risk. Any dynamic content that is passed to a program from the outside must be checked thoroughly or escaped before being used in dynamic statements. This can be done using the system class CL_ABAP_DYN_PRG or the predefined function escape.