I had a requirement in which I wanted to dynamically run this query. Has anyone have worked on this kind of query?
READ TABLE table_name TRANSPORTING feild_name INTO table_name
WITH KEY key_feild1 = value1,
key_feild2 = value2,
key_feild3 = value3.
READ TABLE has dynamic syntax when specifying secondary keys (here) and key components (here), but in a limited fashion.
I think LOOP AT is the command you are looking for. More details about the usage and example here. Look at Part 4:
Dynamic WHERE Condition cond_syntax can be specified as a
character-like data object or standard table with character-like row
type
Dummy code:
LOOP AT table INTO line WHERE (condition).
EXIT. --> Exit at first found line.
ENDLOOP.
IF sy-subrc = 0.
...
ENDIF.
Here is one more possible solution, based on this answer. Though, it is a bit ugly, but it definitely works.
DATA: table_tab TYPE TABLE OF rsdstabs,
selid TYPE rsdynsel-selid,
cond_tab TYPE rsds_twhere,
field_tab TYPE TABLE OF rsdsfields,
string TYPE string.
FIELD-SYMBOLS <cond> LIKE LINE OF cond_tab.
table_tab = VALUE #( ( prim_tab = 'USR02') ).
CALL FUNCTION 'FREE_SELECTIONS_INIT'
EXPORTING
kind = 'T'
IMPORTING
selection_id = selid
TABLES
tables_tab = table_tab
EXCEPTIONS
OTHERS = 4.
IF sy-subrc <> 0.
MESSAGE 'Error in initialization' TYPE 'I' DISPLAY LIKE 'E'.
LEAVE PROGRAM.
ENDIF.
CALL FUNCTION 'FREE_SELECTIONS_DIALOG'
EXPORTING
selection_id = selid
title = 'Free Selection'
as_window = ' '
IMPORTING
where_clauses = cond_tab
TABLES
fields_tab = field_tab
EXCEPTIONS
OTHERS = 4.
IF sy-subrc <> 0.
MESSAGE 'No free selection created' TYPE 'I'.
LEAVE PROGRAM.
ENDIF.
FIELD-SYMBOLS: <fld> TYPE any.
DATA: field1 TYPE c LENGTH 10, value1 TYPE string,
field2 TYPE c LENGTH 10, value2 TYPE string,
field3 TYPE c LENGTH 10, value3 TYPE string,
field4 TYPE c LENGTH 10, value4 TYPE string,
field5 TYPE c LENGTH 10, value5 TYPE string,
field6 TYPE c LENGTH 10, value6 TYPE string,
field7 TYPE c LENGTH 10, value7 TYPE string,
field8 TYPE c LENGTH 10, value8 TYPE string,
field9 TYPE c LENGTH 10, value9 TYPE string,
num1(1) TYPE n,
fldname TYPE fieldname,
valname TYPE fieldname.
ASSIGN cond_tab[ tablename = 'USR02' ] TO <cond>.
IF sy-subrc = 0.
LOOP AT <cond>-where_tab ASSIGNING FIELD-SYMBOL(<fs_cond>).
num1 = sy-tabix.
CONCATENATE 'field' num1 INTO fldname.
CONCATENATE 'value' num1 INTO valname.
ASSIGN (fldname) TO <fld>. "assigning field name
string = <fs_cond>.
REPLACE REGEX `(^.*\(\s)(.*)(EQ.*)` IN string WITH '$2'.
<fld> = string.
ASSIGN (valname) TO <fld>. "assigning value
string = <fs_cond>.
REPLACE REGEX `(.*EQ\s)'(.*)('\s*\))` IN string WITH '$2'.
<fld> = string.
ENDLOOP.
ENDIF.
SELECT *
FROM usr02
INTO TABLE #DATA(lt_usr).
READ TABLE lt_usr ASSIGNING FIELD-SYMBOL(<fs_usr>)
WITH KEY (field1) = value1
(field2) = value2
(field3) = value3
(field4) = value4
(field5) = value5
(field6) = value6
(field7) = value7
(field8) = value8
(field9) = value9.
The sample is built on USR02 table.
At first, on the dynamic selection screen we specify necessary selections fields (keys for READ TABLE) and their values.
Then FREE_SELECTIONS_INIT FM builds WHERE condition based on these fields.
We parse this condition and fetch populated field names and values.
In a READ TABLE statement template, empty fields are simply ignored and table is read only by populated keys.
Related
I am trying to split internal table to smaller chunks.
In below example the internal table big_table is split into small tables.
My question is how do we get the actual data from lt_small_tables for further processing.
TYPES: BEGIN OF lty_line,
column1 TYPE i,
column2 TYPE c LENGTH 4,
END OF lty_line.
CONSTANTS: lc_test_data_amount TYPE i VALUE 44,
lc_split_at_amount TYPE i VALUE 7,
DATA: lt_big_table TYPE STANDARD TABLE OF lty_line,
lv_string TYPE string,
lt_small_tables TYPE STANDARD TABLE OF REF TO data,
lr_small_table TYPE REF TO data.
FIELD-SYMBOLS: <lg_target> TYPE STANDARD TABLE.
" Generate test data
DO lc_test_data_amount TIMES.
CALL FUNCTION 'GENERAL_GET_RANDOM_STRING'
EXPORTING number_chars = 4 " Specifies the number of generated chars
IMPORTING random_string = lv_string. " Generated string
APPEND VALUE #( column1 = sy-index
column2 = CONV #( lv_string ) ) TO lt_big_table.
ENDDO.
" Split
DATA(lo_descr) = CAST cl_abap_tabledescr(
cl_abap_typedescr=>describe_by_data( lt_big_table ) ).
LOOP AT lt_big_table ASSIGNING FIELD-SYMBOL(<ls_line>).
IF ( sy-tabix - 1 ) MOD lc_split_at_amount = 0.
CREATE DATA lr_small_table TYPE HANDLE lo_descr.
ASSERT lr_small_table IS BOUND.
APPEND lr_small_table TO lt_small_tables.
ASSIGN lr_small_table->* TO <lg_target>.
ASSERT <lg_target> IS ASSIGNED.
ENDIF.
APPEND <ls_line> TO <lg_target>.
ENDLOOP.
Thanks,
Kris
There are at least a couple of ways
Solution 1: cast internal table reference into a known type, so that you can directly access its fields.
FIELD-SYMBOLS: <fs_table> like lt_big_table.
LOOP AT lt_small_tables into lr_small_table.
ASSIGN lr_small_table->* TO <fs_table>.
ASSERT <fs_table> IS ASSIGNED.
LOOP AT <fs_table> into data(ls_line).
" do something with line
write: / ls_line-column1, ls_line-column2.
ENDLOOP.
ENDLOOP.
Solution 2: dynamic access to the tables fields
FIELD-SYMBOLS: <generic_fs_table> TYPE ANY TABLE.
LOOP AT lt_small_tables into lr_small_table.
ASSIGN lr_small_table->* TO <generic_fs_table>.
ASSERT sy-subrc = 0.
LOOP AT <generic_fs_table> ASSIGNING FIELD-SYMBOL(<generic_fs_line>).
" dinamically access to line fields
ASSIGN COMPONENT 'COLUMN1' of STRUCTURE <generic_fs_line> to FIELD-SYMBOL(<generic_fs_field1>).
ASSERT sy-subrc = 0.
ASSIGN COMPONENT 'COLUMN2' of STRUCTURE <generic_fs_line> to FIELD-SYMBOL(<generic_fs_field2>).
ASSERT sy-subrc = 0.
" do something with component2
write: / <generic_fs_field1>, <generic_fs_field2>.
ENDLOOP.
ENDLOOP.
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.
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.
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.
I have function module which imports my_values
my_values is an custom internal table type of string.
This "my_values" variable contains for example: ["foo", "bar"]
I want to select all values from table Z_MYTAB where the column my_col is in my_values.
I tried this:
SELECT * FROM Z_MYTAB WHERE
my_col in #my_values INTO TABLE #DATA(my_rows).
But this fails with an error message:
table my_values has wrong row structure
(The message was translated to English. The original could be slightly different)
I could loop over my_values but I would like to avoid this.
How to do SQL IN with host variables which are internal tables?
Selection with IN is possible only with a range table.
Conversion of an internal table into a range table can be done like this:
DATA ltr_value TYPE RANGE OF string.
ltr_value = VALUE #( FOR <my_value> IN my_values
( sign = 'I'
option = 'EQ'
low = <my_value> )
).
IN openands could be of 2 types:
SELECT ... WHERE my_col IN ( value1, value2 , value3)
in this case no host expression can be used as right operand
SELECT ... WHERE my_col IN sel_tab[]
in this case sel_tab is a range like
So you could use the following:
DATA sel_tab type range of string.
sel_tab = value #( for ls in my_values ( sign = 'I' option = 'EQ' low = ls ) ).
SELECT * FROM Z_MYTAB WHERE
my_col in #sel_tab[] INTO TABLE #DATA(my_rows).
Best regards
User JozsefSzikszai pointed me to "SELECT FOR ALL ENTRIES".
I found this in the docs:
For an elementary row type, the pseudo component table_line must be specified for comp.
See: https://help.sap.com/doc/abapdocu_752_index_htm/7.52/en-US/abenwhere_logexp_itab.htm
IF my_values is initial.
exit.
endif.
SELECT * FROM Z_MYTAB
FOR ALL ENTRIES IN #my_values WHERE
column_name = #my_values-table_line
INTO TABLE #DATA(result_rows).
I have requirement to provider customer search help for user and data to be retrieved from application server directory.
Following is the detail of directory and File type.
Application Server Directory: /usr/sap/tmp/
File type extension .txt should only be available in search help.
Custom Search help should display Directory Name and File having extension .txt.
Users should not be able to select files from any other directory.
Example of Search help output:
Directory Name File Name
-------------- --------------
/usr/sap/tmp/ file_name1.txt
/usr/sap/tmp/ file_name2.txt
/usr/sap/tmp/ file_name3.txt
Following links are helpful but my requirement is not fulfilled.
https://archive.sap.com/discussions/thread/285999
F4_FILENAME
cl_gui_frontend_services=>directory_browse
/SAPDMC/LSM_F4_SERVER_FILE
https://archive.sap.com/discussions/thread/715635
F4_DXFILENAME_TOPRECURSION
is there any one who has better solution?
regards,
Umar Abdullah
Doesn't function module /SAPDMC/LSM_F4_SERVER_FILE fullfil your requirement?
Edit:
In order for users to not be able to select anything from different directories, you can write a wrapper around the function call to make sure the right directory is selected.
Probably not the ideal solution, but one that requires no development effort.
CONSTANTS:
lco_directory TYPE char30 VALUE '/usr/sap/tmp/',
lco_filemask TYPE char5 VALUE '*'.
DATA:
lv_filename TYPE rlgrap-filename,
lv_path TYPE string.
WHILE 1 NE 2.
CLEAR: lv_filename, lv_path.
CALL FUNCTION '/SAPDMC/LSM_F4_SERVER_FILE'
EXPORTING
directory = lco_directory
filemask = lco_filemask
IMPORTING
serverfile = lv_filename
EXCEPTIONS
canceled_by_user = 1
OTHERS = 2.
IF sy-subrc = 0 AND sy-ucomm NE 'CANC' AND lv_filename IS NOT INITIAL.
CALL FUNCTION 'TRINT_SPLIT_FILE_AND_PATH'
EXPORTING
full_name = lv_filename
IMPORTING
file_path = lv_path
EXCEPTIONS
x_error = 1
OTHERS = 2 .
IF sy-subrc = 0 AND lv_path NE lco_directory.
* Wrong directory was chosen
MESSAGE 'Invalid directory' TYPE 'S' DISPLAY LIKE 'W'.
ELSE.
* Directory is ok
EXIT.
ENDIF.
ELSE.
* Action cancelled
CLEAR: lv_filename, lv_path.
EXIT.
ENDIF.
ENDWHILE.
I have created custom logic for the requirement. I would like to share.
REPORT YUA_LIST_DIRECTORY.
CLASS ff_intf DEFINITION.
PUBLIC SECTION.
METHODS: listdirectory IMPORTING iv_dir TYPE c
EXPORTING ev_ldir TYPE c ev_file TYPE c ,
get_file_list IMPORTING iv_ldir TYPE c iv_today TYPE c.
TYPES: BEGIN OF t_directory,
log_name TYPE dirprofilenames,
phys_path TYPE dirname_al11,
END OF t_directory.
DATA: lt_int_list TYPE TABLE OF abaplist,
lt_string_list TYPE list_string_table,
lt_directories TYPE TABLE OF t_directory,
ls_directory TYPE t_directory.
DATA: BEGIN OF gs_file,
directory(500) TYPE c, " name of directory.
name(75) TYPE c, " name of entry." (possibly truncated.)
type(10) TYPE c, " type of entry: directory, file
len(16) TYPE p, " length in bytes
owner(8) TYPE c, " owner of the entry
mtime(6) TYPE p, " last modification date, " seconds since 1970
mode(9) TYPE c, " like "rwx-r-x--x":" protection mode
errno(3) TYPE c,
errmsg(40) TYPE c,
mod_date TYPE d,
mod_time(8) TYPE c, " hh:mm:ss
subrc LIKE sy-subrc,
END OF gs_file.
DATA:
ls_file LIKE gs_file,
pt_file LIKE TABLE OF gs_file.
CLASS-METHODS: p6_to_date_time_tz IMPORTING iv_time TYPE p EXPORTING ev_time TYPE c ev_date TYPE d.
ENDCLASS. "ff_intf DEFINITION
*----------------------------------------------------------------------*
* CLASS ff_intf IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS ff_intf IMPLEMENTATION.
METHOD listdirectory.
FIELD-SYMBOLS: <l_line> TYPE string.
CONCATENATE 'FF' sy-datum '.txt' INTO ev_file. " file name
SUBMIT rswatch0 EXPORTING LIST TO MEMORY AND RETURN.
CALL FUNCTION 'LIST_FROM_MEMORY'
TABLES
listobject = lt_int_list.
CALL FUNCTION 'LIST_TO_ASCI'
EXPORTING
with_line_break = 'X' "abap_true
IMPORTING
list_string_ascii = lt_string_list
TABLES
listobject = lt_int_list.
* remove the separators and the two header lines
DELETE lt_string_list WHERE table_line CO '-'.
DELETE lt_string_list INDEX 1.
DELETE lt_string_list INDEX 1.
* parse the individual lines
LOOP AT lt_string_list ASSIGNING <l_line>.
* If you're on a newer system, you can do this in a more elegant way using regular expressions
CONDENSE <l_line>.
SHIFT <l_line> LEFT DELETING LEADING '|'.
SHIFT <l_line> RIGHT DELETING TRAILING '|'.
SPLIT <l_line>+1 AT '|' INTO ls_directory-log_name ls_directory-phys_path.
APPEND ls_directory TO lt_directories.
ENDLOOP.
READ TABLE lt_directories INTO ls_directory WITH KEY log_name = iv_dir .
IF sy-subrc EQ 0.
ev_ldir = ls_directory-phys_path.
ENDIF.
ENDMETHOD. "listdirectory
METHOD get_file_list.
DATA:
l_counter TYPE i,
l_counter_package TYPE i,
l_char10(10),
l_text(100),
l_subrc LIKE sy-subrc,
lv_cmptoday TYPE c LENGTH 11.
*-----------------------------------*
DATA lv_compstr TYPE c LENGTH 5.
lv_compstr = '*.TXT'.
CONCATENATE '*' sy-datum+0(4) sy-datum+4(2) sy-datum+6(2) '*' INTO lv_cmptoday. " YYYYMMDD
CALL 'C_DIR_READ_FINISH'
ID 'ERRNO' FIELD ls_file-errno
ID 'ERRMSG' FIELD ls_file-errmsg.
CALL 'C_DIR_READ_START'
ID 'DIR' FIELD iv_ldir " logical directory
ID 'FILE' FIELD '*'
ID 'ERRNO' FIELD ls_file-errno
ID 'ERRMSG' FIELD ls_file-errmsg.
IF sy-subrc <> 0.
IF NOT ls_file-errmsg IS INITIAL.
MESSAGE i034(/sapdmc/lsmw_obj_060) WITH ls_file-errmsg.
ENDIF.
EXIT.
ENDIF.
DO .
CLEAR ls_file.
CALL 'C_DIR_READ_NEXT'
ID 'TYPE' FIELD ls_file-type
ID 'NAME' FIELD ls_file-name
ID 'LEN' FIELD ls_file-len
ID 'OWNER' FIELD ls_file-owner
ID 'MTIME' FIELD ls_file-mtime
ID 'MODE' FIELD ls_file-mode
ID 'ERRNO' FIELD ls_file-errno
ID 'ERRMSG' FIELD ls_file-errmsg.
l_subrc = sy-subrc.
ls_file-subrc = sy-subrc.
IF l_subrc = 1.
EXIT.
ELSEIF l_subrc = 5.
ls_file-type = '???'.
ls_file-owner = '???'.
ls_file-mode = '???'.
ENDIF.
ls_file-directory = iv_ldir.
ADD 1 TO l_counter.
ADD 1 TO l_counter_package.
IF l_counter_package = 100.
l_text = '& Enteries Read'.
l_char10 = l_counter.
REPLACE '&' WITH l_char10 INTO l_text.
CALL FUNCTION 'SAPGUI_PROGRESS_INDICATOR'
EXPORTING
text = l_text.
l_counter_package = 0.
ENDIF.
* Machine time into date/time of day convert
IF iv_today EQ 'X'. " only files of current date
CALL METHOD ff_intf=>p6_to_date_time_tz( EXPORTING iv_time = ls_file-mtime
IMPORTING ev_time = ls_file-mod_time ev_date = ls_file-mod_date ).
IF ls_file-mod_date EQ sy-datum.
* Only the files, which fit the sample(mask)
CASE ls_file-type(1).
WHEN 'F' OR 'f'. " File
IF ( ls_file-name CP lv_compstr ) AND ls_file-name+0(2) = 'FF' AND ls_file-name CP lv_cmptoday. " Only Text File to compare
APPEND ls_file TO pt_file.
ENDIF.
* WHEN OTHERS.
* APPEND ls_file TO pt_file.
ENDCASE.
ENDIF.
ELSE. " ALL files in directory
* Only the files, which fit the sample(mask)
CASE ls_file-type(1).
WHEN 'F' OR 'f'. " File
IF ( ls_file-name CP lv_compstr ) AND ls_file-name+0(2) = 'FF'. " Only Text File to compare and PODEL & Today
APPEND ls_file TO pt_file.
ENDIF.
ENDCASE.
ENDIF.
ENDDO.
SORT pt_file BY type DESCENDING name DESCENDING.
CALL 'C_DIR_READ_FINISH'
ID 'ERRNO' FIELD ls_file-errno
ID 'ERRMSG' FIELD ls_file-errmsg.
ENDMETHOD. "get_file_list
METHOD p6_to_date_time_tz.
DATA: opcode TYPE x,
unique, not_found,
timestamp TYPE i,
date TYPE d,
time TYPE t,
tz LIKE sy-zonlo,
timestring(10),
abapstamp(14),
abaptstamp TYPE timestamp.
timestamp = iv_time.
IF sy-zonlo = space.
* Der Benutzer hat keine Zeitzone gepflegt: nehme lokale des App. Srv.
CALL FUNCTION 'TZON_GET_OS_TIMEZONE'
IMPORTING
ef_timezone = tz
ef_not_unique = unique
ef_not_found = not_found.
IF unique = 'X' OR not_found = 'X'. .
tz = sy-tzone.
CONCATENATE 'UTC+' tz INTO tz.
ENDIF.
ELSE.
tz = sy-zonlo.
ENDIF.
* wandle den Timestamp in ABAP Format um und lass den ABAP konvertieren
opcode = 3.
CALL 'RstrDateConv'
ID 'OPCODE' FIELD opcode
ID 'TIMESTAMP' FIELD timestamp
ID 'ABAPSTAMP' FIELD abapstamp.
abaptstamp = abapstamp.
CONVERT TIME STAMP abaptstamp TIME ZONE tz INTO DATE date
TIME time.
IF sy-subrc <> 0.
date = abapstamp(8).
time = abapstamp+8.
ENDIF.
WRITE: time(2) TO timestring(2),
':' TO timestring+2(1),
time+2(2) TO timestring+3(2),
':' TO timestring+5(1),
time+4(2) TO timestring+6(2).
MOVE timestring TO ev_time.
MOVE date TO ev_date.
ENDMETHOD. "P6_TO_DATE_TIME_TZ
ENDCLASS.
DATA lo_pi TYPE REF TO ff_intf.
DATA ls_pt LIKE LINE OF lo_pi->pt_file.
DATA v_csv TYPE c LENGTH 1 VALUE space.
DATA v_separator TYPE c LENGTH 2.
DATA: lt_file TYPE ztt_file,
ls_file LIKE LINE OF lt_file,
ls_ptfile LIKE LINE OF lo_pi->pt_file.
SELECTION-SCREEN: BEGIN OF BLOCK a WITH FRAME TITLE text-001.
PARAMETERS p_dir TYPE c LENGTH 50 DEFAULT '/usr/sap/tmp/'.
PARAMETERS: p_sfile LIKE rlgrap-filename.
SELECTION-SCREEN: END OF BLOCK a.
AT SELECTION-SCREEN OUTPUT.
AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_sfile.
REFRESH lo_pi->pt_file.
CALL METHOD lo_pi->get_file_list( EXPORTING iv_ldir = p_dir iv_today = '' ). " Directory logical name.
REFRESH lt_file.
LOOP AT lo_pi->pt_file INTO ls_ptfile.
MOVE ls_ptfile-directory TO ls_file-directory.
MOVE ls_ptfile-name TO ls_file-fname.
APPEND ls_file TO lt_file.
ENDLOOP.
CALL FUNCTION 'F4IF_INT_TABLE_VALUE_REQUEST'
EXPORTING
retfield = 'FNAME'
dynpprog = sy-repid
dynpnr = sy-dynnr
dynprofield = 'so_tmpl-low'
value_org = 'S'
TABLES
value_tab = lt_file
EXCEPTIONS
parameter_error = 1
no_values_found = 2
OTHERS = 3.
CASE sy-subrc.
WHEN 1.
MESSAGE 'Parameter Error' TYPE 'I' DISPLAY LIKE 'W'.
WHEN 2.
MESSAGE 'No values found' TYPE 'I' DISPLAY LIKE 'W'.
WHEN 3.
MESSAGE 'Error Processing help' TYPE 'I' DISPLAY LIKE 'W'.
ENDCASE.
********************************* INITIALIZATION. ************************************
INITIALIZATION.
CREATE OBJECT lo_pi.
********************************* START-OF-SELECTION ************************************
START-OF-SELECTION.
********************************* END-OF-SELECTION ************************************
END-OF-SELECTION.
I have the name of a table DATA lv_tablename TYPE tabname VALUE 'xxxxx', and a generic FIELD-SYMBOLS: <lt_table> TYPE ANY TABLE. which contains entries selected from that corresponding table.
I've defined my line structure FIELD-SYMBOLS: <ls_line> TYPE ANY. which i'd use for reading from the table.
Is there a way to create a READ statement on <lt_table> fully specifying the key fields?
I am aware of the statement / addition READ TABLE xxxx WITH KEY (lv_field_name) = 'asdf'., but this however wouldn't work (afaik) for a dynamic number of key fields, and I wouldn't like to create a large number of READ TABLE statements with an increasing number of key field specifications.
Can this be done?
Actually i found this to work
DATA lt_bseg TYPE TABLE OF bseg.
DATA ls_bseg TYPE bseg.
DATA lv_string1 TYPE string.
DATA lv_string2 TYPE string.
lv_string1 = ` `.
lv_string2 = lv_string1.
SELECT whatever FROM wherever INTO TABLE lt_bseg.
READ TABLE lt_bseg INTO ls_bseg
WITH KEY ('MANDT') = 800
(' ') = ''
('BUKRS') = '0005'
('BELNR') = '0100000000'
('GJAHR') = 2005
('BUZEI') = '002'
('') = ''
(' ') = ''
(' ') = ' '
(lv_string1) = '1'
(lv_string2) = ''.
By using this syntax one can just specify as many key fields as required. If some fields will be empty, then these will just get ignored, even if values are specified for these empty fields.
One must pay attention that using this exact syntax (static definitions), 2 fields with the exact same name (even blank names) will not be allowed.
As shown with the variables lv_string1 and lv_string2, at run-time this is no problem.
And lastly, one can specify the fields in any order (i don't know what performance benefits or penalties one might get while using this syntax)
There seems to be the possibility ( like a dynamic select statement whith binding and lt_dynwhere ).
Please refer to this post, there was someone, who also asked for the requirement:
http://scn.sap.com/thread/1789520
3 ways:
READ TABLE itab WITH [TABLE] KEY (comp1) = value1 (comp2) = value2 ...
You can define a dynamic number of key fields by indicating statically the maximum number of key fields in the code, and indicate at runtime some empty key field names if there are less key fields to be used.
LOOP AT itab WHERE (where) (see Addition 4 "WHERE (cond_syntax)")
Available since ABAP 7.02.
SELECT ... FROM #itab WHERE (where) ...
Available since ABAP 7.52. It may be slow if the condition is complex and cannot be handled by the ABAP kernel, i.e. it needs to be executed by the database. In that case, only few databases are supported (I think only HANA is supported currently).
Examples (ASSERT statements are used here to prove that the conditions are true, otherwise the program would fail):
TYPES: BEGIN OF ty_table_line,
key_name_1 TYPE i,
key_name_2 TYPE i,
attr TYPE c LENGTH 1,
END OF ty_table_line,
ty_internal_table TYPE SORTED TABLE OF ty_table_line WITH UNIQUE KEY key_name_1 key_name_2.
DATA(itab) = VALUE ty_internal_table( ( key_name_1 = 1 key_name_2 = 1 attr = 'A' )
( key_name_1 = 1 key_name_2 = 2 attr = 'B' ) ).
"------------------ READ TABLE
DATA(key_name_1) = 'KEY_NAME_1'.
DATA(key_name_2) = 'KEY_NAME_2'.
READ TABLE itab WITH TABLE KEY
(key_name_1) = 1
(key_name_2) = 2
ASSIGNING FIELD-SYMBOL(<line>).
ASSERT <line> = VALUE ty_table_line( key_name_1 = 1 key_name_2 = 2 attr = 'B' ).
key_name_2 = ''. " ignore this key field
READ TABLE itab WITH TABLE KEY
(key_name_1) = 1
(key_name_2) = 2 "<=== will be ignored
ASSIGNING FIELD-SYMBOL(<line_2>).
ASSERT <line_2> = VALUE ty_table_line( key_name_1 = 1 key_name_2 = 1 attr = 'A' ).
"------------------ LOOP AT
DATA(where) = 'key_name_1 = 1 and key_name_2 = 1'.
LOOP AT itab ASSIGNING FIELD-SYMBOL(<line_3>)
WHERE (where).
EXIT.
ENDLOOP.
ASSERT <line_3> = VALUE ty_table_line( key_name_1 = 1 key_name_2 = 1 attr = 'A' ).
"---------------- SELECT ... FROM #itab
SELECT SINGLE * FROM #itab WHERE (where) INTO #DATA(line_3).
ASSERT line_3 = VALUE ty_table_line( key_name_1 = 1 key_name_2 = 1 attr = 'A' ).