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
CONSTANTS left TYPE tabname VALUE 'SFLIGHT'.
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.
FIELD-SYMBOLS <itab> TYPE STANDARD TABLE.
cl_demo_input=>request(
EXPORTING text = `Right Table of Join`
CHANGING field = right ).
DATA(whitelist) = VALUE whitelist( ( `SPFLI` )
( `SCARR` )
( `SAPLANE` ) ).
TRY.
right = cl_abap_dyn_prg=>check_whitelist_tab(
val = to_upper( right )
whitelist = whitelist ).
CATCH cx_abap_not_in_whitelist.
cl_demo_output=>write(
`Only the following tables are allowed:` ).
cl_demo_output=>display( whitelist ).
LEAVE PROGRAM.
ENDTRY.
first_on = abap_true.
CLEAR select.
CLEAR sublist.
CLEAR from.
READ CURRENT LINE LINE VALUE INTO right.
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.
ENDLOOP.
LOOP AT comp_tab2 INTO DATA(comp2) WHERE name IS NOT INITIAL.
TRY.
comp1 = comp_tab1[ KEY primary_key name = comp2-name ].
IF first_on = abap_false.
from = from && ` and `.
ELSE.
first_on = abap_false.
ENDIF.
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.
ENDTRY.
ENDLOOP.
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 ``.
TRY.
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( ) ).
ENDTRY.
Description
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
.