2

If I have a tabkey value, e.g., DATA(lv_tabkey) = '1000041508773180000013000'., which is the concatenated value of all table keys for an entry and I know the name of the corresponding table:

How I can get the table entry for it without splitting tabkey manually and therefore having to write the order and length of each key field?

Full example:

" The first 3 chars always belong to the 'mandt' field 
" which can't be filtered in the SELECT, therefore 
" I ignore it and start with key2
DATA(lv_tabkey) = '1000041508773180000013000'.

"ToDo - how to make this generic? - START
DATA(lv_key2) = lv_tabkey+3(12).
DATA(lv_key3) = lv_tabkey+15(3).
DATA(lv_key4) = lv_tabkey+18(4).
DATA(lv_key5) = lv_tabkey+22(3).
DATA(lv_where) =      'key2 = ' && lv_key2 && 
                 ' AND key3 = ' && lv_key3 && 
                 ' AND key4 = ' && lv_key4 && 
                 ' AND key5 = ' && lv_key5.
"ToDo - how to make this generic? - END

SELECT *
  FROM table_x
  INTO TABLE DATA(lt_results)
  WHERE (lv_where).

I think I have to somehow iterate over the table fields, find out the keys and their length - but I don't know how to do this.

Sandra Rossi
  • 11,934
  • 5
  • 22
  • 48
Cold_Class
  • 3,214
  • 4
  • 39
  • 82
  • Unless it's a Z table, Can you post the actual table you are actually trying to access? I think what you need is to have a ``JOIN`` to the table where the tabkey is stored as a single field, so you can ``SELECT from table_x`` without splitting. – RaTiO Apr 22 '20 at 07:46
  • `how to make this generic?` no way. You always need to know the table (structure), field lengths, and the set of fields used for key. Only with these 3 parameters and RTTS you can construct generic method for parsing the key. – Suncatcher Apr 22 '20 at 08:35
  • @Suncatcher then I don't know the correct wording for this - maybe dynamic? I just mean not having to do those '+18(4)'-things in the code manually. – Cold_Class Apr 22 '20 at 09:11
  • @RaTiO but this question is about doing this for any table in general, that's why the actual table should not matter - so unless table_x also has a "tabkey" field, I don't see what a `JOIN` could do, if the tables have no common unique fields – Cold_Class Apr 22 '20 at 09:14
  • Please edit your question: add one example because people don't understand what you mean. – Sandra Rossi Apr 22 '20 at 10:04

2 Answers2

2

The statement you are seeking is:

ASSIGN tabkey TO < structure> CASTING TYPE HANDLE r_type_struct.

Knowing type handle for the (table key) structure you can fill it with values in a generic way and query the table using the structure. Here is how:

DATA: handle      TYPE REF TO data,
      lref_struct TYPE REF TO cl_abap_structdescr.

FIELD-SYMBOLS: <key_fld> TYPE abap_componentdescr.

SELECT * UP TO 5000 ROWS
  FROM cdpos
  INTO TABLE @DATA(t_cdpos)
  WHERE tabname NOT LIKE '/%'.

LOOP AT t_cdpos ASSIGNING FIELD-SYMBOL(<fs_cdpos>).
  lref_struct ?= cl_abap_structdescr=>describe_by_name( <fs_cdpos>-tabname ).

* get key fields
  DATA(key_fields) = VALUE ddfields( FOR line IN lref_struct->get_ddic_field_list( ) WHERE ( keyflag NE space ) ( line ) ).

* filling key field components
  DATA(key_table) = VALUE abap_component_tab( FOR ls_key IN key_fields
                                              ( name = ls_key-fieldname
                                                type = CAST #( cl_abap_datadescr=>describe_by_name( ls_key-domname ) )
                                               )
                                            ).
* create key fields type handle
  TRY.
      DATA(r_type_struct) = cl_abap_structdescr=>create( key_table ).
    CATCH cx_sy_struct_creation .
  ENDTRY.

* create key type
  CHECK r_type_struct IS NOT INITIAL.
  CREATE DATA handle TYPE HANDLE r_type_struct.
  ASSIGN handle->* TO FIELD-SYMBOL(<structure>).

* assigning final key structure
  ASSIGN <fs_cdpos>-tabkey TO <structure> CASTING TYPE HANDLE r_type_struct.

* filling values
  LOOP AT key_table ASSIGNING <key_fld>.
    ASSIGN COMPONENT <key_fld>-name OF STRUCTURE <structure> TO FIELD-SYMBOL(<val>).
    CHECK sy-subrc = 0.
    <key_fld>-suffix = <val>.
  ENDLOOP.

  DATA(where_cond) = REDUCE string( INIT where = ` ` FOR <field> IN key_table WHERE ( name <> 'MANDT' ) NEXT where = where && <field>-name && ` = '` && <field>-suffix && `' AND ` ).
  where_cond = substring( val = where_cond off = 0 len = strlen( where_cond ) - 4 ).

  IF <fs_cdpos>-tabname = 'BNKA'.
    SELECT *
    INTO TABLE @DATA(lt_bnka)
    FROM bnka
    WHERE (where_cond).
  ENDIF.

ENDLOOP.

Here I built the sample on table CDPOS that contain table names and additionally concatenated key values in field tabkey, in other words exactly what you are trying to use.

In a loop it detects table types, builds the key and make SQL query in a generic way. Here I used table BNKA for simplicity, but SQL SELECT can be generized as well via field-symbol. Also I made a trick by filling values into the same tab that contains structure components, in SUFFIX field.

P.S. Before passing where condition into query make proper data type validation to avoid such errors as SAPSQL_DATA_LOSS, because with new syntax it makes a strict check.

Suncatcher
  • 10,355
  • 10
  • 52
  • 90
  • Wow, I didn't expect it to be that difficult - but it is exactly what I was looking for and works perfectly - thanks!!! – Cold_Class Apr 23 '20 at 16:48
1

your use case reminds me that how I deal with Change Document key.(CDHDR/CDPOS). Hope it helps!

DATA:
  lv_tabkey  TYPE char50,
  ls_table   TYPE table_x.
FIELD-SYMBOLS:
  <ls_src_x> TYPE x,
  <ls_tgt_x> TYPE x.

"Add Client info the Table key if your table is Client dependent. 
CONCATENATE sy-mandt lv_tabkey INTO lv_tabkey.

ASSIGN lv_tab_key TO <ls_src_x> CASTING.
ASSIGN ls_table TO <ls_tgt_x> CASTING.
<ls_tgt_x> = <ls_src_x>.

"Now ls_table has the key info filled including MANDT if you have the MANDT in table key. 

SELECT *
  FROM table_x
    INTO TABLE DATA(lt_results)
    WHERE key2 = ls_table-key2 AND key3 = ls_table-key3
          AND key4 = ls_table-key4 AND key5 = ls_table_key5.
Haojie
  • 5,665
  • 1
  • 15
  • 14