I am trying to use table from another report program as in the following:
REPORT ZSAM3.
TYPES: BEGIN OF ty_report,
rec_acc TYPE skont,
vendor TYPE LFA1-LIFNR,
jan_deb TYPE BSEG-WRBTR,
jan_cred TYPE BSEG-WRBTR,
feb_deb TYPE BSEG-WRBTR,
feb_cred TYPE BSEG-WRBTR,
mar_deb TYPE BSEG-WRBTR,
mar_cred TYPE BSEG-WRBTR,
apr_deb TYPE BSEG-WRBTR,
apr_cred TYPE BSEG-WRBTR,
may_deb TYPE BSEG-WRBTR,
may_cred TYPE BSEG-WRBTR,
jun_deb TYPE BSEG-WRBTR,
jun_cred TYPE BSEG-WRBTR,
jul_deb TYPE BSEG-WRBTR,
jul_cred TYPE BSEG-WRBTR,
aug_deb TYPE BSEG-WRBTR,
aug_cred TYPE BSEG-WRBTR,
sep_deb TYPE BSEG-WRBTR,
sep_cred TYPE BSEG-WRBTR,
oct_deb TYPE BSEG-WRBTR,
oct_cred TYPE BSEG-WRBTR,
nov_deb TYPE BSEG-WRBTR,
nov_cred TYPE BSEG-WRBTR,
dec_deb TYPE BSEG-WRBTR,
dec_cred TYPE BSEG-WRBTR,
acc_bal_deb TYPE BSEG-WRBTR,
acc_bal_cred TYPE BSEG-WRBTR,
END OF ty_report,
tt_report TYPE TABLE OF ty_report.
DATA: lt_report TYPE tt_report,
lv_ukurs type tcurr-ukurs,
Tcurr1 type tcurr,
fieldname(4) type c,
fnamedebit(20) type c,
fnamecredit(20) type c.
FIELD-SYMBOLS: <fs_rep> LIKE LINE OF lt_report.
select single ukurs from tcurr
into lv_ukurs
where fcurr = 'EUR'
and tcurr = 'AUD'. "<- your local currency
DATA lr_pay_data TYPE REF TO data.
FIELD-SYMBOLS: <lt_pay_data> TYPE ANY TABLE,
<pos_data> type any.
cl_salv_bs_runtime_info=>set(
EXPORTING display = abap_false
metadata = abap_false
structure = ''
data = abap_true ).
SUBMIT RFKSLD00 via SELECTION-SCREEN and return.
TRY.
ASSIGN lr_pay_data->* TO <lt_pay_data>.
>>> cl_salv_bs_runtime_info=>get_data(
IMPORTING t_data = <lt_pay_data> ).
CATCH cx_salv_bs_sc_runtime_info.
MESSAGE `Unable to retrieve ALV data` TYPE 'E'.
ENDTRY.
LOOP AT <lt_pay_data> ASSIGNING <pos_data>.
APPEND INITIAL LINE to lt_report ASSIGNING <fs_rep>.
MOVE-CORRESPONDING <pos_data> TO <fs_rep>.
WRITE: / <pos_data>.
ENDLOOP.
Write: 'Program End!'.
I am getting the following runtime error:
you attenpted to access an anassigned field symbol (data segment 12)
Maybe (as suggested by arrows in the code) that <'lt_pay_data'> has not been initialized or assigned but I do not know how assign any table type variable.
This could be what's going on in your program:
PROGRAM zref.
DATA lr_pay_data TYPE REF TO data.
FIELD-SYMBOLS <lt_pay_data> TYPE ANY TABLE.
From F1 on ASSIGN: " If the reference variable dref does not reference a data object, the assignment is not performed and sy-subrc is set to 4 "
ASSIGN lr_pay_data->* TO <lt_pay_data>.
IF sy-subrc <> 0.
MESSAGE 'You need to CREATE DATA for your REF TO variable before dereferencing it' TYPE 'S'.
ENDIF.
Related
I have the following code:
DATA: lt_matnr TYPE TABLE OF mara,
ls_matnr TYPE mara,
lv_werk TYPE werks_d VALUE 'WERK',
lt_stoc_int TYPE TABLE OF zmm_s_stock_list,
lt_stoc TYPE TABLE OF zsd_stock_list,
ls_stoc TYPE zsd_stock_list.
SELECT matnr
FROM mara
INTO CORRESPONDING FIELDS OF TABLE lt_matnr.
LOOP AT lt_matnr INTO ls_matnr.
CALL FUNCTION 'Z_MM_LIST_STOC_MATERIAL_WERKS'
EXPORTING
IP_MATNR = ls_matnr-matnr
IP_WERKS = lv_werk
IMPORTING
ET_STOCK_EXP = lt_stoc_int.
LOOP AT lt_stoc_int ASSIGNING FIELD-SYMBOL(<ls_stoc_int>).
MOVE-CORRESPONDING <ls_stoc_int> TO ls_stoc.
* + other data processing ...
APPEND ls_stoc TO lt_stoc.
ENDLOOP.
ENDLOOP.
INSERT zsd_stock_list FROM TABLE lt_stoc.
Everything works fine until the INSERT statement where I get the following short-dump:
Runtime error: DBSQL_DBSL_LENGTH_ERROR
Exception: CX_SY_OPEN_SQL_DB
Error analysis:
An exception has occurred which is explained in more detail below. The
exception, which is assigned to class 'CX_SY_OPEN_SQL_DB' was not caught an
therefore caused a runtime error. The reason for the exception is:
While accessing a database, the length of a field in ABAP does not
match the size of the corresponding database field.
This can happen for example if a string is bound to a database field
that is shorter than the current string.
It makes little sense because lt_stoc is TYPE TABLE OF zsd_stock_list, how can the field length not match ?
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.
For internal usage I need to define a structured type with one of the fields being a char-field with a variable length.
Something like this (I hope this example clarifies my problem):
DATA: lv_type TYPE char7.
lv_type = 'char128'. "The actual length will be determined during execution of the program
TYPES: BEGIN OF ty_satzcounter,
satza TYPE zedist,
addit TYPE (lv_type), "<----- Something like this (obviously, it doesn't work like
" this, but I think it clarifies my question)
menge TYPE int1,
END OF ty_satzcounter.
DATA: lt_satzcounter TYPE TABLE OF ty_satzcounter,
ls_satzcounter TYPE ty_satzcounter.
...
...
This kind of dynamic typing is not possible, but for your purpose, character type with dynamic length, there is the type string:
TYPES: satza TYPE zedist,
addit TYPE string,
...
I am absolutely with JozsefSzikszai's solution, but for demonstrating the additional complexity of dynamic structures and tables, here a possible solution as example:
"your input
DATA(lv_charlength) = 128.
"or
DATA(lv_type) = 'CHAR128'.
DATA:
lro_structdescr TYPE REF TO cl_abap_structdescr,
lro_tabledescr TYPE REF TO cl_abap_tabledescr,
lro_datadescr TYPE REF TO cl_abap_datadescr,
lro_typedescr TYPE REF TO cl_abap_typedescr,
lt_component TYPE abap_component_tab,
ls_component TYPE LINE OF abap_component_tab,
lro_wa TYPE REF TO data.
FIELD-SYMBOLS: <fs_wa> TYPE any.
FIELD-SYMBOLS: <fs_tab> TYPE table.
* determine components of structure -> lt_component
ls_component-name = 'SATZA'.
ls_component-type ?= cl_abap_elemdescr=>describe_by_name( 'ZEDIST' ).
APPEND ls_component TO lt_component.
ls_component-name = 'ADDIT'.
ls_component-type ?= cl_abap_elemdescr=>get_c( p_length = lv_charlength ).
APPEND ls_component TO lt_component.
"or
* ls_component-name = 'ADDIT'.
* ls_component-type ?= cl_abap_elemdescr=>describe_by_name( lv_type ).
* APPEND ls_component TO lt_component.
ls_component-name = 'MENGE'.
ls_component-type ?= cl_abap_elemdescr=>describe_by_name( 'INT1' ).
APPEND ls_component TO lt_component.
* get structure descriptor -> lro_STRUCTDESCR
lro_structdescr ?= cl_abap_structdescr=>create( lt_component ).
* create work area of structure lro_STRUCTDESCR -> lro_WA
CREATE DATA lro_wa TYPE HANDLE lro_structdescr.
* ASSIGN lro_wa->* TO <fs_wa>. "work area/structure to use
lro_datadescr ?= lro_structdescr.
lro_tabledescr ?= cl_abap_tabledescr=>create( lro_datadescr ).
* Create dynmaic internal table
CREATE DATA et_range_tab TYPE HANDLE lro_tabledescr.
* ASSIGN et_range_tab->* TO <fs_tab>. "table to use
I am pasting this program for example but i will never know the type of the table (here vbap and vbak).
My goals is to display my field symbol without knowing the types.
Is it possible ?
Here is my code :
REPORT ZTEST_FME_FOL.
type-pools slis .
FIELD-SYMBOLS : <mytable> TYPE ANY TABLE.
DATA : lv_alv_table TYPE REF TO cl_salv_table,
lv_funct TYPE REF TO cl_salv_functions,
lv_columns TYPE REF TO cl_salv_columns_table,
lv_column TYPE REF TO CL_SALV_COLUMN_table.
SELECT * from vbap INNER JOIN VBAK ON vbap~vbeln = vbak~vbeln UP TO 10 ROWS INTO TABLE <mytable>.
TRY.
cl_salv_table=>factory(
IMPORTING
r_salv_table = lv_alv_table
CHANGING
t_table = <mytable> ).
CATCH cx_salv_msg .
ENDTRY.
lv_funct = lv_alv_table->get_functions( ).
lv_funct->set_all( Abap_True ).
lv_columns = lv_alv_table->get_columns( ).
lv_alv_table->display( ).
Thanks in advance !
Depending on what you 're trying to do there's going to be more validation required than what I've done, but in essence this is what you need.
Using (dynamic) joins may be particularly tricky.
report zevw_test_dynamic_alv.
parameters: p_table type string obligatory.
field-symbols: <gt_table> type standard table.
data: gt_data type ref to data.
start-of-selection.
create data gt_data type table of (p_table).
assign gt_data->* to <gt_table>.
select * from (p_table) up to 10 rows
into table <gt_table>.
perform display_results using <gt_table>. "Your ALV stuff will be in here
You may even have to build the fieldcat manually and then use
call method cl_alv_table_create=>create_dynamic_table
exporting
it_fieldcatalog = gt_fieldcat[]
importing
ep_table = gt_data.
to get the data reference
I am new to ABAP, and I am creating ALV using FM 'REUSE_ALV_FIELDCATALOG_MERGE' and 'REUSE_ALV_GRID_DISPLAY'.
It is working when I defined internal table IT_MARD using obsolete occurs 0 definition. But I am getting Exception condition "NO_FIELDCATALOG_AVAILABLE" raised, when I defined internal table using type standard table. Could you please explain difference between these two definition and why it is not working in the latter case. The following is the code.
REPORT ztest_fieldcatalog3.
TYPE-POOLS:slis.
*Semi Automatic Fieldcatalog Generation.
*DATA: BEGIN OF IT_MARD OCCURS 0,
* MATNR LIKE MARD-MATNR,
* WERKS LIKE MARD-WERKS, ""
* LGORT LIKE MARD-LGORT,
* PSTAT LIKE MARD-PSTAT,
* END OF IT_MARD.
TYPES: BEGIN OF ty_mard,
matnr type mard-matnr,
werks type mard-werks,
lgort type mard-lgort,
pstat type mard-pstat,
END OF ty_mard.
DATA: IT_MARD TYPE STANDARD TABLE OF ty_mard.
"Use function module create Fieldcat.
DATA:l_program TYPE sy-repid VALUE sy-repid.
DATA:i_fieldcat TYPE slis_t_fieldcat_alv.
SELECT matnr
werks
lgort
pstat
FROM mard
INTO CORRESPONDING FIELDS OF TABLE it_mard
UP TO 100 ROWS.
CALL FUNCTION 'REUSE_ALV_FIELDCATALOG_MERGE'
EXPORTING
i_program_name = l_program
i_internal_tabname = 'IT_MARD'
i_inclname = l_program
i_bypassing_buffer = 'X'
CHANGING
ct_fieldcat = i_fieldcat[].
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
"Call ALV and pass fieldcatalog and data
CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY'
EXPORTING
i_callback_program = l_program
it_fieldcat = i_fieldcat
TABLES
t_outtab = it_mard.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
The difference is that OCCURS creates a table with a header line, while TYPE STANDARD TABLE OF does not (unless you explicitly tell it to). I suppose that the function module is able to guess the structure from a table with a header line, but not a table without a header line. My suggestions would be to
use a data dictionary structure instead of a local structure - it's easier to maintain and extend later on and
don't use the REUSE function modules, but check the CL_SALV_* classes instead since they are officially supported and have a much cleaner API