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.
Related
I am currently trying to create a report with a dynamically created internal table (the number of columns can be different every time).
Is there a way how I can address the generated columns while filling the structure of the given table?
Here is the code I am working with:
FIELD-SYMBOLS: <fcat> TYPE lvc_s_fcat,
<fcat_aus> TYPE ANY TABLE.
IF so_datum-high <> ''.
DATA(lv_month_diff) = so_datum-high - so_datum-low.
ELSE.
DATA(lv_month) = so_datum-low.
ENDIF.
APPEND INITIAL LINE TO gt_fcat ASSIGNING <fcat>.
<fcat>-fieldname = 'MATNR'.
<fcat>-tabname = 'GZ_TABLE'.
<fcat>-ref_field = 'MATNR'.
<fcat>-ref_table = 'MAKT'.
APPEND INITIAL LINE TO gt_fcat ASSIGNING <fcat>.
<fcat>-fieldname = 'MAKTX'.
<fcat>-tabname = 'GZ_TABLE'.
<fcat>-ref_field = 'MAKTX'.
<fcat>-ref_table = 'MAKT'.
DATA(lv_counter) = 1.
DO 10 TIMES.
DATA(lv_fieldname_qt) = 'MOQ' && lv_counter.
DATA(lv_fieldname_fqt) = 'MFQ' && lv_counter.
lv_counter = lv_counter + 1.
APPEND INITIAL LINE TO gt_fcat ASSIGNING <fcat>.
<fcat>-fieldname = lv_fieldname_qt.
<fcat>-tabname = 'GZ_TABLE'.
<fcat>-ref_field = 'MNG01'.
<fcat>-ref_table = 'MDEZ'.
APPEND INITIAL LINE TO gt_fcat ASSIGNING <fcat>.
<fcat>-fieldname = lv_fieldname_fqt.
<fcat>-tabname = 'GZ_TABLE'.
<fcat>-ref_field = 'MNG01'.
<fcat>-ref_table = 'MDEZ'.
ENDDO.
CALL METHOD cl_alv_table_create=>create_dynamic_table
EXPORTING
it_fieldcatalog = gt_fcat
IMPORTING
ep_table = gz_table
EXCEPTIONS
generate_subpool_dir_full = 1
OTHERS = 2.
ASSIGN gz_table->* to <fcat_aus>.
Maybe one of you has an idea.
Thanks in advance!
Use the ASSIGN COMPONENT statement to access a structure component dynamically. Check the ABAP documentation (F1) for further details. You can specify the component by index or by field name.
Here is an example to complete Thomas answer (note that I don't explain how to create a table dynamically with CREATE DATA as it's not your question, here it's created statically with 2 components, I only explain how to fill an internal table by referring to it dynamically):
TYPES: BEGIN OF ty_line,
comp1 TYPE i,
text_component TYPE string,
END OF ty_line,
ty_itab TYPE STANDARD TABLE OF ty_line WITH DEFAULT KEY.
DATA r_itab TYPE REF TO DATA.
DATA r_line TYPE REF TO DATA.
FIELD-SYMBOLS <itab> TYPE STANDARD TABLE.
FIELD-SYMBOLS <line> TYPE ANY.
FIELD-SYMBOLS <component> TYPE ANY.
" create an internal table, here it's the static way, but you may also use CREATE DATA
" to create it dynamically
CREATE DATA r_itab TYPE ty_itab.
ASSIGN r_itab->* TO <itab>.
" now let's fill it dynamically, first define a line
CREATE DATA r_line LIKE LINE OF <itab>.
ASSIGN r_line->* TO <line>.
ASSIGN COMPONENT 1 OF <line> TO <component>. " access to COMP1 component
IF sy-subrc = 0.
<component> = 30.
ENDIF.
ASSIGN COMPONENT 'TEXT_COMPONENT' OF <line> TO <component>.
IF sy-subrc = 0.
<component> = 'text'.
ENDIF.
" now add the line
INSERT <line> INTO TABLE <itab>.
Note that it's possible to access the whole line with ASSIGN COMPONENT 0 ... (especially useful if the internal table has none component).
More information:
ASSIGN
->* (dereferencing operator)
CREATE DATA
I want to create a function/custom class method that takes in 2 parameters:
1) IM_ITAB type ANY TABLE
2) IM_COMPONENT type STRING
and returns 1 parameter:
1) EX_RANGE type PIQ_SELOPT_T
So, algorithm is like this:
First of all, we check if the column with a component name at all exists
Then, we check that internal table is not empty.
Then, we loop through internal table assigning component and filling range table. Code is below.
METHODS compose_range_from_itab
IMPORTING
IM_ITAB type ANY TABLE
IM_COMPONENT type STRING
EXPORTING
EX_RANGE type PIQ_SELOPT_T.
...
METHOD compose_range_from_itab.
DATA: lo_obj TYPE REF TO cl_abap_tabledescr,
wa_range TYPE selopt,
lt_range TYPE piq_selopt_t.
FIELD-SYMBOLS: <fs_line> TYPE ANY,
<fs_component> TYPE ANY.
lo_obj ?= cl_abap_typedescr=>describe_by_data( p_data = im_itab ).
READ TABLE lo_obj->key TRANSPORTING NO FIELDS WITH KEY name = im_component.
IF sy-subrc IS INITIAL.
IF LINES( im_itab ) GT 0.
LOOP AT im_itab ASSIGNING <fs_line>.
ASSIGN COMPONENT im_component OF STRUCTURE <fs_line> TO <fs_component>.
wa_range-sign = 'I'.
wa_range-option = 'EQ'.
wa_range-low = <fs_component>.
APPEND wa_range TO lt_range.
ENDLOOP.
SORT lt_range BY low.
DELETE ADJACENT DUPLICATES FROM lt_range COMPARING low.
ex_range[] = lt_range[].
ENDIF.
ENDIF.
ENDMETHOD.
But I want to improve the method further. If the imported internal table has, let's say, 255 columns, then it will take longer to loop through such table. But I need only one column to compose the range.
So I want to get components of internal table, then choose only one component, create a new line type containing only that component, then create internal table with that line type and copy.
Here is the pseudo code corresponding to what I want to achieve:
append corresponding fields of im_itab into new_line_type_internal_table.
How can I "cut out" one component and create a new line type using RTTS?
You are overcomplicating everything, you don't need RTTS for that.
DEFINE make_range.
ex_range = VALUE #( BASE ex_range ( sign = 'I' option = 'EQ' low = &1 ) ).
END-OF-DEFINITION.
LOOP AT im_itab ASSIGNING FIELD-SYMBOL(<fs_line>).
ASSIGN COMPONENT im_component OF STRUCTURE <fs_line> TO FIELD-SYMBOL(<fs_field>).
CHECK sy-subrc = 0 AND <fs_field> IS NOT INITIAL.
make_range <fs_field>.
ENDLOOP.
And yes, as Sandra said, you won't gain any performance with RTTS, just the opposite.
Surprisingly, this variant turned out to be faster:
CLASS-METHODS make_range_variant_2
IMPORTING
sample TYPE table_type
column TYPE string
RETURNING
VALUE(result) TYPE range_type.
METHOD make_range_variant_2.
TYPES:
BEGIN OF narrow_structure_type,
content TYPE char32,
END OF narrow_structure_type.
TYPES narrow_table_type TYPE STANDARD TABLE OF narrow_structure_type WITH EMPTY KEY.
DATA narrow_table TYPE narrow_table_type.
DATA(mapping) =
VALUE cl_abap_corresponding=>mapping_table_value(
( kind = cl_abap_corresponding=>mapping_component srcname = column dstname = 'CONTENT' ) ).
DATA(mover) =
cl_abap_corresponding=>create_with_value(
source = sample
destination = narrow_table
mapping = mapping ).
mover->execute(
EXPORTING
source = sample
CHANGING
destination = narrow_table ).
LOOP AT narrow_table ASSIGNING FIELD-SYMBOL(<row>).
INSERT VALUE #(
sign = 'I'
option = 'EQ'
low = <row>-content )
INTO TABLE result.
ENDLOOP.
ENDMETHOD.
CL_ABAP_CORRESPONDING delegates to a kernel function for the structure-to-structure move, which apparently is faster than the ABAP-native ASSIGN COMPONENT [...] OF STRUCTURE [...] TO FIELD-SYMBOL [...]. The actual loop then seems to be faster because it uses fixed-name assignments.
Maybe somebody could verify.
I would not go for a Macro.
Data:
lr_data type ref to data.
FIELD-SYMBOLS:
<lv_component> TYPE any,
<ls_data> TYPE any.
CREATE DATA lr_data LIKE LINE OF im_itab.
ASSIGN lr_data->* TO <ls_data>.
"Check whether im_component exists
ASSIGN COMPONENT im_component OF STRUCTURE <ls_data> TO <lv_component>.
CHECK sy-subrc EQ 0.
LOOP AT im_itab INTO <ls_data>.
APPEND VALUE #( sign = 'I' option = 'EQ' low = <lv_component> ) TO ex_range.
ENDLOOP.
In an ITAB I have 3 fields: ACCOUNT-OBJECT_AMOUNT and a sample is:
64000 KAGR1 10
64000 KAGR1 15
64010 KAGR1 20
64010 KAGR2 15
64020 KAGR2 10
64020 KAGR2 10
And I want the display to be like the below:
KAGR1 KAGR2
64000 25
64010 20 15
64020 30
Can anyone know how to display it in an ALV?
Thanks
Here is a generic solution. Note that the method show_table_grouped_by has no knowledge of the type of the table, so it can be used with any table, although I bet there are some field types that would break the dynamic code. The data to display can have multiple fields that will be used as keys (your example only has one) and one field that is used for the columns (i_group_by) and one field that is used to aggregate from (i_aggregate_from). Most of the idea of this program comes from this blog, however the solution below is more dynamic. The complete program processes the data as provided in the question, with the value in the last line corrected to come to the result in the example.
If you know that the values for your group by field will be limited to a certain number of values you can make a less dynamic solution that will probably be more efficient.
REPORT zso_group_alv.
TYPES: BEGIN OF ts_data,
field1 TYPE char10,
group TYPE char10,
val TYPE i,
END OF ts_data,
tt_data TYPE STANDARD TABLE OF ts_data.
DATA: gt_data TYPE tt_data.
CLASS lcl_alv_grouped DEFINITION.
PUBLIC SECTION.
CLASS-METHODS:
show_table_grouped_by IMPORTING VALUE(it_data) TYPE ANY TABLE
i_group_by TYPE fieldname
i_aggregate_from TYPE fieldname,
group_fld_name IMPORTING i_value TYPE any
RETURNING VALUE(fld_name) TYPE fieldname.
ENDCLASS.
CLASS lcl_alv_grouped IMPLEMENTATION.
METHOD group_fld_name.
" Returns the field name for the group fields
" This is to make sure there are no reserved names used or
" reuse of already existing fields
fld_name = 'fld_' && i_value.
ENDMETHOD.
METHOD show_table_grouped_by.
" Shows the data in table IT_DATA in an ALV
" The data is transposed
" The data from field I_AGGREGATE_FROM is summed into groups
" from the values in the field I_GROUP_BY
" All the other fields in the table are treated as the key
" fields for the transposed table
DATA: ls_component TYPE cl_abap_structdescr=>component,
lt_components TYPE cl_abap_structdescr=>component_table,
lr_struct TYPE REF TO cl_abap_structdescr,
lt_keys TYPE abap_sortorder_tab,
lt_key_components TYPE cl_abap_structdescr=>component_table,
"ls_keys TYPE REF TO data,
lr_trans_table TYPE REF TO data,
lr_trans_wa TYPE REF TO data,
lr_keys_type TYPE REF TO cl_abap_structdescr,
ls_keys TYPE REF TO data,
ls_keys_prev TYPE REF TO data,
lr_salv TYPE REF TO cl_salv_table.
FIELD-SYMBOLS: <trans_table> TYPE STANDARD TABLE.
" Determine the fields in the transposed table
LOOP AT it_data ASSIGNING FIELD-SYMBOL(<data>).
AT FIRST.
" Get field to aggregate
ASSIGN COMPONENT i_aggregate_from OF STRUCTURE <data> TO FIELD-SYMBOL(<aggregate_field>).
IF sy-subrc NE 0.
RETURN. " Would be nice to tell the calling program about this error
ENDIF.
" Gather all the other fields from the data table, these are treated as keys
lr_struct ?= cl_abap_datadescr=>describe_by_data( <data> ).
LOOP AT lr_struct->get_components( ) ASSIGNING FIELD-SYMBOL(<component>).
IF <component>-name NE i_aggregate_from AND
<component>-name NE i_group_by.
APPEND <component> TO: lt_components,
lt_key_components.
APPEND VALUE #( name = <component>-name
descending = abap_false
astext = abap_true
) TO lt_keys.
ENDIF.
ENDLOOP.
ENDAT. " FIRST
" Get the group by field
ASSIGN COMPONENT i_group_by OF STRUCTURE <data> TO FIELD-SYMBOL(<group_field>).
IF sy-subrc NE 0.
RETURN. " Would be nice to tell the calling program about this error
ENDIF.
" Gather all the values in the group by field
DATA(l_new_group) = group_fld_name( <group_field> ).
READ TABLE lt_components WITH KEY name = l_new_group TRANSPORTING NO FIELDS.
IF sy-subrc NE 0.
ls_component-name = l_new_group.
ls_component-type ?= cl_abap_datadescr=>describe_by_data( <aggregate_field> ).
APPEND ls_component TO lt_components.
ENDIF.
ENDLOOP. " IT_DATA
" LT_COMPONENTS is now filled with all the fields to show in the ALV
" Create the transpose table and fill its
DATA(lr_trans_table_type) = cl_abap_tabledescr=>create( cl_abap_structdescr=>create( lt_components ) ).
CREATE DATA lr_trans_table TYPE HANDLE lr_trans_table_type.
ASSIGN lr_trans_table->* TO <trans_table>.
" Data needs to be sorted to generate the rows in the transposed table
SORT it_data BY (lt_keys).
" Create structures to keep track of the key values
lr_keys_type ?= cl_abap_structdescr=>create( lt_key_components ).
CREATE DATA ls_keys TYPE HANDLE lr_keys_type.
CREATE DATA ls_keys_prev TYPE HANDLE lr_keys_type.
ASSIGN ls_keys->* TO FIELD-SYMBOL(<keys>).
ASSIGN ls_keys_prev->* TO FIELD-SYMBOL(<keys_prev>).
" Transpose the data
LOOP AT it_data ASSIGNING <data>.
MOVE-CORRESPONDING <data> TO <keys>.
IF <keys> NE <keys_prev>.
" Found a new key combination, add a row to the transposed table
APPEND INITIAL LINE TO <trans_table> ASSIGNING FIELD-SYMBOL(<trans_data>).
MOVE-CORRESPONDING <data> TO <trans_data>. " Filling the key fields
ENDIF.
" Agragate the value into the right group
ASSIGN COMPONENT i_aggregate_from OF STRUCTURE <data> TO FIELD-SYMBOL(<value>).
ASSIGN COMPONENT i_group_by OF STRUCTURE <data> TO FIELD-SYMBOL(<group>).
ASSIGN COMPONENT group_fld_name( <group> ) OF STRUCTURE <trans_data> TO FIELD-SYMBOL(<trans_value>).
ADD <value> TO <trans_value>.
" Remember keys to compare with the next row
<keys_prev> = <keys>.
ENDLOOP. " IT_DATA
" Display transposed data in ALV
TRY.
cl_salv_table=>factory(
* EXPORTING
* list_display = IF_SALV_C_BOOL_SAP=>FALSE " ALV Displayed in List Mode
* r_container = " Abstract Container for GUI Controls
* container_name =
IMPORTING
r_salv_table = lr_salv " Basis Class Simple ALV Tables
CHANGING
t_table = <trans_table>
).
CATCH cx_salv_msg. "
" Some error handling would be nice
ENDTRY.
" Will need to do something about the column headers
lr_salv->display( ).
ENDMETHOD.
ENDCLASS.
START-OF-SELECTION.
APPEND VALUE #( field1 = '64000' group = 'KAGR1' val = 10 ) TO gt_data.
APPEND VALUE #( field1 = '64000' group = 'KAGR1' val = 15 ) TO gt_data.
APPEND VALUE #( field1 = '64010' group = 'KAGR1' val = 20 ) TO gt_data.
APPEND VALUE #( field1 = '64010' group = 'KAGR2' val = 15 ) TO gt_data.
APPEND VALUE #( field1 = '64020' group = 'KAGR2' val = 10 ) TO gt_data.
APPEND VALUE #( field1 = '64020' group = 'KAGR2' val = 20 ) TO gt_data.
lcl_alv_grouped=>show_table_grouped_by(
EXPORTING
it_data = gt_data
i_group_by = 'GROUP'
i_aggregate_from = 'VAL'
).
I have a selection screen with select-options where I want to enter several information about materials, for example: material number etc.
The user is also able to enter a language which the output should be in.
If the user chooses english the program shall display an internal table with material number, language, material name in english. If the user enters spanish, I want the output to be in spanish.
What do I have to do in order to define a dynamic structure / table which shows the respective columns dependent on the chosen language?
Thanks for your help
It's highly-dependent on the data structure you are going to show to user, but usually you don't need dynamic structure for this, but rather need to populate data dynamically, i.e. depending on current user language.
For example, material texts are stored in MAKT text table, where texts are stored along with language keys by which they are usually retrieved:
SELECT
a~matnr
a~werks
b~maktx FROM ekpo AS a
INNER JOIN makt AS b
ON b~matnr = a~matnr
AND b~spras = sy-langu
INTO CORRESPONDING FIELDS OF TABLE int_out
WHERE
a~matnr IN s_matnr and
a~werks IN s_werks.
Other descriptions in SAP are usually stored in text tables as well.
More about sy-langu and other system fields is here.
UPDATE: If you really want a dynamic structure with all the languages, see this sample:
DATA: lang TYPE SPRAS.
* language selection
SELECT-OPTIONS: s_lang FOR lang.
SELECT a~matnr, a~werks, b~maktx, b~spras UP TO 5000 ROWS
FROM ekpo AS a
JOIN makt AS b
ON b~matnr = a~matnr
INTO TABLE #DATA(int_out)
WHERE a~werks LIKE '3%'
AND a~matnr LIKE '1%'
AND b~spras IN #s_lang.
*finding unique languages
DATA lt_langs TYPE TABLE OF spras.
lt_langs = VALUE #( ( '' ) ).
LOOP AT int_out ASSIGNING FIELD-SYMBOL(<fs_out>)
GROUP BY ( lang = to_upper( val = <fs_out>-spras ) ) ASCENDING
WITHOUT MEMBERS
ASSIGNING FIELD-SYMBOL(<ls_lang>).
APPEND <ls_lang>-lang TO lt_langs.
ENDLOOP.
DATA :
ls_component TYPE cl_abap_structdescr=>component,
gt_components TYPE cl_abap_structdescr=>component_table.
*adding MATNR column
ls_component-name = 'MATNR'.
ls_component-type ?= cl_abap_datadescr=>describe_by_name( 'matnr' ).
APPEND ls_component TO gt_components.
*Creating dynamic structure with column for every lang
LOOP AT lt_langs ASSIGNING FIELD-SYMBOL(<fs_lang>).
CONDENSE <fs_lang>.
IF <fs_lang> IS NOT INITIAL.
ls_component-name = 'makt_' && <fs_lang>.
ls_component-type ?= cl_abap_datadescr=>describe_by_name( 'maktx' ).
APPEND ls_component TO gt_components.
ENDIF.
ENDLOOP.
* constructing dynamic structure
DATA: gr_struct_typ TYPE REF TO cl_abap_datadescr.
gr_struct_typ ?= cl_abap_structdescr=>create( p_components = gt_components ).
* constructing table from structure
DATA: gr_dyntable_typ TYPE REF TO cl_abap_tabledescr.
gr_dyntable_typ = cl_abap_tabledescr=>create( p_line_type = gr_struct_typ ).
DATA: gt_dyn_table TYPE REF TO data,
gw_dyn_line TYPE REF TO data.
FIELD-SYMBOLS: <gfs_line>,<gfs_line1>,<fs1>,
<gfs_dyn_table> TYPE STANDARD TABLE.
CREATE DATA: gt_dyn_table TYPE HANDLE gr_dyntable_typ,
gt_dyn_table TYPE HANDLE gr_dyntable_typ,
gw_dyn_line TYPE HANDLE gr_struct_typ.
ASSIGN gt_dyn_table->* TO <gfs_dyn_table>.
ASSIGN gw_dyn_line->* TO <gfs_line>.
LOOP AT int_out ASSIGNING <fs_out>.
* checking for duplicated
READ TABLE <gfs_dyn_table> ASSIGNING <gfs_line1> WITH KEY ('MATNR') = <fs_out>-matnr.
IF sy-subrc = 0.
CONTINUE.
ENDIF.
* assigning material number
LOOP AT gt_components ASSIGNING FIELD-SYMBOL(<fs_component>).
IF <fs_component>-name = 'MATNR'.
ASSIGN COMPONENT <fs_component>-name OF STRUCTURE <gfs_line> TO <fs1>.
IF <fs1> IS ASSIGNED.
<fs1> = <fs_out>-matnr.
UNASSIGN <fs1>.
ENDIF.
ENDIF.
* assigning languge-dependent names
READ TABLE int_out WITH KEY matnr = <fs_out>-matnr
spras = <fs_component>-name+5
ASSIGNING FIELD-SYMBOL(<fs_spras>).
IF sy-subrc = 0.
ASSIGN COMPONENT <fs_component>-name OF STRUCTURE <gfs_line> TO <fs1>.
IF <fs1> IS ASSIGNED.
<fs1> = <fs_spras>-maktx.
UNASSIGN <fs1>.
ENDIF.
ENDIF.
ENDLOOP.
APPEND <gfs_line> TO <gfs_dyn_table>.
CLEAR: <gfs_line>.
ENDLOOP.
DATA: l_lang TYPE spras VALUE 'E'.
* showing values in proper language depending on user input
LOOP AT <gfs_dyn_table> ASSIGNING <gfs_line>.
ASSIGN COMPONENT 'makt_' && l_lang OF STRUCTURE <gfs_line> TO <fs1>.
IF <fs1> IS ASSIGNED.
WRITE / <fs1>.
UNASSIGN <fs1>.
ENDIF.
ENDLOOP.
I'm working on a routine which moves the lines of a string table (in this case fui_elements) into a structure of unknown type (fcwa_struct).
DATA(li_temp) = ... "fill assignment table here
LOOP AT fui_elements ASSIGNING FIELD-SYMBOL(<lfs_element>).
ASSIGN COMPONENT li_temp[ sy-tabix ] OF STRUCTURE fcwa_struct
TO FIELD-SYMBOL(<lfs_field>).
IF sy-subrc <> 0.
"somethings wrong with the fui_elements data
ENDIF.
<lfs_field> = <lfs_element>.
ENDLOOP.
If the table i_field_customizing (STANDARD TABLE OF string) is not initial, I want to use its values.
Otherwise I want to generate an integer table (so that the loop runs equally often regardless of the table's values). Here lw_max is the amount of fields the imported structure has:
DATA(li_temp) = COND #( WHEN i_field_customizing[] IS INITIAL
THEN VALUE t_integer_tt( FOR X = 1
THEN X + 1
WHILE X <= lw_max
( X ) )
ELSE i_field_customizing ).
But when I run the report with i_field_customizing like that:
DATA(i_field_customizing) = VALUE t_string_tt( ( `KUNNR` ) ( `NAME1` ) ).
I get this exception on the line where I try to construct li_temp:
CX_SY_CONVERSION_NO_NUMBER (KUNNR cannot be interpreted as a number)
My current guess is that COND gets its type statically. Does anybody know how I can get around this?
What you are trying to achieve will not be possible because the type of an inline definition of a variable using COND is decided at compilation time and not at runtime.
Please see my question here. The type that will be taken is always the type of the variable that stands directly after THEN. You can decide what type will be chosen at compilation time by fiddling with negating the condition and switching places of variables after THEN at ELSE but it will be always either or and from what I understand you want to be able to do it dynamically so your ASSIGN COMPONENT statement works as expected with integers.
Even by specifically casting the variable after ELSE one gets the same short dump as you do.
DATA(li_temp) = COND #( WHEN i_field_customizing IS INITIAL
THEN VALUE t_integer_tt( ( 1 ) ( 2 ) )
ELSE CAST t_string_tt( REF #( i_field_customizing ) )->* ).
Alternatively you could cast to REF TO DATA but then you have to dereference it to a field symbol of type STANDARD TABLE.
REPORT zzy.
CLASS lcl_main DEFINITION FINAL CREATE PRIVATE.
PUBLIC SECTION.
CLASS-METHODS:
main.
ENDCLASS.
CLASS lcl_main IMPLEMENTATION.
METHOD main.
TYPES:
t_integer_tt TYPE STANDARD TABLE OF i WITH EMPTY KEY,
t_string_tt TYPE STANDARD TABLE OF string WITH EMPTY KEY.
FIELD-SYMBOLS:
<fs_table> TYPE STANDARD TABLE.
DATA: BEGIN OF l_str,
kunnr TYPE kunnr,
name1 TYPE name1,
END OF l_str.
* DATA(i_field_customizing) = VALUE t_string_tt( ( `KUNNR` ) ( `NAME1` ) ).
DATA(i_field_customizing) = VALUE t_string_tt( ).
DATA(li_temp) = COND #( WHEN i_field_customizing IS INITIAL
THEN CAST data( NEW t_integer_tt( ( 1 ) ( 2 ) ) )
ELSE CAST data( REF #( i_field_customizing ) ) ).
ASSIGN li_temp->* TO <fs_table>.
LOOP AT <fs_table> ASSIGNING FIELD-SYMBOL(<fs_temp>).
ASSIGN COMPONENT <fs_temp> OF STRUCTURE l_str TO FIELD-SYMBOL(<fs_field>).
ENDLOOP.
ENDMETHOD.
ENDCLASS.
START-OF-SELECTION.
lcl_main=>main( ).