How to assign internal table into a structure and then to a field in ABAP - abap

With the below code I can retrieve the content of the internal table t_t005e, however when put into the field wa_upload-region, only the first column of the data is retrieved, however I want to retrieve the third column data.
TYPES: BEGIN OF ty_upload,
" ...
region TYPE regio,
" ...
END OF ty_upload.
DATA: wa_upload TYPE ty_upload,
t_t005e TYPE STANDARD TABLE OF t005e.
READ TABLE t_t005e
INTO wa_upload-region
WITH KEY land1 = 'GB'
regio = 'YK'
counc = ''.
As a result, I have created a work area wa_t005e, with the same type as the lines of t_t005e.
I want to first read the internal table t_t005e into the work area wa_t005e, then to the field wa_upload-region.
Following is my work in progress:
DATA: wa_t005e TYPE t005e.
LOOP AT t_t005e INTO wa_t005e.
ASSIGN COMPONENT wa_t005e-regio OF STRUCTURE
wa_t005e TO <wa_upload-region>.
ENDLOOP.
How to get the data of wa_t005e-regio into the field wa_upload-region?

There is no way of reading the value of only one column from a table directly into one field of a structure, at least in systems pre-7.40. If you do have a 7.40 system, you can use a "table expression" like this:
TRY.
wa_upload-region = t_t005e[ land1 = 'GB' regio = 'YK' counc = '' ]-regio.
CATCH cx_sy_itab_line_not_found.
ENDTRY.
In older system, you will have to read the whole table line into a structure, then you can just take the field from it, like this:
READ TABLE t_t005e INTO wa_t005e WITH KEY land1 = 'GB' regio = 'YK' counc = ''.
wa_upload-region = wa_t005e-regio.
If you want to use ASSIGN and the like, you can do that too. First you would read the table line into a structure again (in this case a field symbol to stay in theme). Then assign the needed component/field of the structure to a single-value field symbol.
DATA: t_upload TYPE STANDARD TABLE OF ty_upload,
t_t005e TYPE STANDARD TABLE OF t005e.
FIELD-SYMBOLS: <fs_upload> TYPE ty_upload,
<fs_t005e> TYPE t005e,
<region> TYPE regio. " or type any
SELECT *
FROM t005e
INTO CORRESPONDING FIELDS OF TABLE t_t005e.
READ TABLE t_t005e ASSIGNING <fs_t005e> WITH KEY land1 = 'GB' regio = 'YK' counc = ''.
ASSIGN COMPONENT 'REGIO' OF STRUCTURE <fs_t005e> TO <region>. " <---
*Other option: number of column
*ASSIGN COMPONENT 3 OF STRUCTURE <fs_t005e> TO <region>.
APPEND INITIAL LINE TO t_upload ASSIGNING <fs_upload>.
<fs_upload>-region = <region>.
WRITE <fs_upload>-region.
But is reading only one entry from the table really what you want to do? You didn't specify all keys of t005e in the READ statement. It would only select the first line that fits.

Related

Assigning Field Symbols to Internal Table

I'm trying upload Excel file to internal table in ABAP. I'm using function GUI_UPLOAD and then SCMS_BINARY_TO_XSTRING. At last I have field sybmbol <gt_data> with data from Excel file.
DATA(lo_data_ref) = lo_excel_ref->if_fdt_doc_spreadsheet~get_itab_from_worksheet(
lv_woksheetname ).
*-- Excel work sheet data in dyanmic internal table
ASSIGN lo_data_ref->* TO <gt_data>.
A [CString]
B [CString]
data1
data11
data2
data22
data3
data33
How I can iterate <gt_data> to internal table? I would try like below, but I received dump.
TYPES: BEGIN OF lty_test,
A TYPE string,
B TYPE string,
END OF lty_test.
DATA: lt_test_table TYPE STANDARD TABLE OF lty_test.
As far as I understood, you want to read excel rows with this code.
LOOP AT <gt_data> ASSIGNING FIELD-SYMBOL(<ls_data>).
ENDLOOP.
I am not sure struct of <ls_data> but I think you can read it with index for get to know main idea.
Could you try it like below?
CHECK <gt_data> IS ASSIGNED.
"It's column count for excel file. It can be found dynamically.
DATA(lv_column_count) = 10.
"Loop for rows.
LOOP AT <gt_data> ASSIGNING FIELD-SYMBOL(<ls_data>).
"Loop for columns
DO lv_column_count.
ASSIGN COMPONENT sy-index OF <ls_dat> TO FIELD-SYMBOL(<lfs_value>).
ENDDO.
ENDLOOP.
So first you need to declare a structure for the internal table and each field in the structure should have type "string".
Types:begin of ty_upload,
Field1 type string,
Field2 type string,
End of ty_upload.
Data:it_upload type standard table of ty_upload.
It_upload[] = <gt_data>
Now internal table it_upload should have the data from the field value
Try this:
file = 'C:\xyz.XLS'.
CALL FUNCTION 'ALSM_EXCEL_TO_INTERNAL_TABLE'
EXPORTING
filename = file
i_begin_col = '1'
i_begin_row = '1'
i_end_col = '5'
i_end_row = '6000'
TABLES
intern = xcel
EXCEPTIONS
inconsistent_parameters = 1
upload_ole = 2
OTHERS = 3.
LOOP AT xcel.
" xcel is an internal table and has field xcel-value
ENDLOOP.

Fill arbitrary column in dynamic itab?

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

READ TABLE WITH TABLE KEY does not find record

I'm trying to use the class /ui5/cl_json_parser for parsing a JSON string.
The following code snippet reproduces the problem:
REPORT ztest_json_parse.
DATA: input TYPE string,
output TYPE string,
json_parser TYPE REF TO /ui5/cl_json_parser.
input = '{"address":[{"street":"Road","number":"545"},{"street":"Avenue","number":"15"}]}'.
CREATE OBJECT json_parser.
json_parser->parse( input ).
json_parser->print( ).
output = json_parser->value( path = '/address/1/street' ).
WRITE output.
The print method shows the correct parsed JSON string, but the output variable is always empty.
I have traced the code down to the method VALUE of the class /UI5/CL_JSON_PARSER, at line 15, which contains:
read table m_entries into l_entry with table key parent = l_parent name = l_name.
In the debugger, I can see that l_parent = '/address/1' and l_name = 'street', and that the internal table m_entries contains a record with parent = '/address/1' and name = 'street'. Nevertheless the READ statement always returns sy-subrc = 4 and does not find anything.
Can anyone help?
First: Do not use /ui5/cl_json_parser class, it is intended for internal use ONLY and has no reliable documentation
Secondly, here is the sample how you can fetch street value from the first element of your JSON:
DATA(o_json) = cl_abap_codepage=>convert_to( '{"address":[{"street":"Road","number":"545"},{"street":"Avenue","number":"15"}]' ).
DATA(o_reader) = cl_sxml_string_reader=>create( o_json ).
TRY.
DATA(o_node) = o_reader->read_next_node( ).
WHILE o_node IS BOUND.
DATA(op) = CAST if_sxml_open_element( o_node ).
LOOP AT op->get_attributes( ) ASSIGNING FIELD-SYMBOL(<a>).
DATA(attr) = <a>->get_value( ).
ENDLOOP.
IF attr <> 'street'.
o_node = o_reader->read_next_node( ).
ELSE.
DATA(val) = CAST if_sxml_value_node( o_reader->read_next_node( ) ).
WRITE: '/address/1/street =>', val->get_value( ).
EXIT.
ENDIF.
ENDWHILE.
CATCH cx_root INTO DATA(e_txt).
ENDTRY.
As far as I know, there is no class in ABAP that allows fetching single JSON attributes like XPath.
Certainly agree with Suncatcher on avoid UI5 Json parser.
If you dont control/know the structure of the source data, Suncatchers answer is good.
However,
if you know the basic structure of the source JSON and you must, if you plan to access the first address row, fieldname street .
AND you can have the source provided using uppercase variable names then you can use the so called identity transformation.
types: begin of ty_addr,
street type string,
number type string,
end of ty_addr.
types ty_addr_t type STANDARD TABLE OF ty_addr.
DATA: input TYPE string,
ls_addr TYPE ty_addr,
lt_addr type ty_addr_t.
input = '{"ADDRESS":[{"STREET":"Road","NUMBER":"545"},{"STREET":"Avenue","NUMBER":"15"}]}'.
CALL TRANSFORMATION id SOURCE XML input
RESULT address = lt_addr.
read table lt_addr index 1 into ls_addr.
WRITE ls_addr-street.

Create dynamic ABAP internal table

On selection screen, the user needs to insert a table name, and I need to get first 3 fields from that table and display them in an ALV for the output. What I understand from reading tutorials is that I need to call method cl_alv_table_create=>create_dynamic_table, but I don't know how to create the fieldcatalog.
DATA: t_newtable TYPE REF TO data,
t_fldcat TYPE lvc_t_fcat,
CALL METHOD cl_alv_table_create=>create_dynamic_table
EXPORTING
it_fieldcatalog = t_fldcat
IMPORTING
ep_table = t_newtable.
I assume that the table name which user enters is a data dictionary table (like SFLIGHT). If yes, then you can generate the field catalog as follows.
data : it_tabdescr type abap_compdescr_tab,
wa_tabdescr type abap_compdescr.
data : ref_table_descr type ref to cl_abap_structdescr.
ref_table_descr ?= cl_abap_typedescr=>describe_by_name( p_table ).
it_tabdescr[] = ref_table_descr->components[].
loop at it_tabdescr into wa_tabdescr.
clear wa_fieldcat.
wa_fieldcat-fieldname = wa_tabdescr-name .
wa_fieldcat-datatype = wa_tabdescr-type_kind.
wa_fieldcat-inttype = wa_tabdescr-type_kind.
wa_fieldcat-intlen = wa_tabdescr-length.
wa_fieldcat-decimals = wa_tabdescr-decimals.
append wa_fieldcat to it_fieldcat.
endloop.
Here, "p_table" is the selection screen parameter containing the table
name.

Change field length afterwards

TABLES: VBRK.
DATA: BEGIN OF it_test,
BUKRS LIKE VBRK-BUKRS,
FKDAT LIKE VBRK-FKDAT,
END OF it_test.
DATA: wa_test LIKE it_test.
SELECT * FROM VBRK INTO CORRESPONDING FIELD OF wa_test.
IF wa_test-BUKRS = 'xxxx'.
wa_test-BUKRS = 'XXXXX' "Problem occurs here as the BUKRS allow 4 value
APPEND wa_test TO it_test.
ENDIF.
Then I want to map the internal table to output as ALV table. Is they any way to change the field length afterwards?
Apart from multiple issues in your code, you can't. If you need something similar to that, add an additional field to the structure with whatever size you require and copy the values over.
If the objective is to output something to the screen that is different(or differently formatted) that what is stored internally(or in the database), then the use of a data element with a conversion exit maybe the way to go.
For an example, look at the key fields of table PRPS.
Expanding the answer of vwegert:
The MOVE-CORRESPONDINGcommand (and SELECT ... INTO CORRESPONDING FIELDS) don't need the same field type. The content is converted. So you could define a 5-character field in your internal structure and copy the BUKRS-value into this 5-character field:
TABLES: VBRK.
DATA: BEGIN OF it_test,
BUKRS(5), "longer version of VBRK-BUKRS,
FKDAT LIKE VBRK-FKDAT,
END OF it_test.
DATA: tt_test TYPE STANDARD TABLE OF it_test.
* I would strongly recommend to set a filter!
SELECT * FROM VBRK INTO CORRESPONDING FIELD OF it_test.
IF it_test-BUKRS = 'xxxx'.
it_test-BUKRS = 'XXXXX'.
APPEND it_test to tt_test.
ENDIF.
ENDSELECT.
A pitfall: When you use it with ALV you will loose the field description. (on the other side, the field description of the original field will not fit any longer the new field.)