Map key-value to structure - abap

I have a key-value internal table and want to fill an existing structure with it.
Example: 1st I get a key-value table that I create by reading data from two existing tables.
SELECT vals~attr_value, names~attr_name
FROM atst_attr AS vals
INNER JOIN tc_attr AS names
ON vals~tc_attr_id = names~tc_attr_id
WHERE vals~atst_id = #lv_atst_id
INTO TABLE #DATA(itab)
.
Now my itab looks like this:
itab:
name value
1. "field_a" "value_a"
2. "field_c" "value_c"
And my local structure (or workingarea as it is often called) is empty:
l_struc:
field_a: ""
field_b: ""
field_c: ""
Now I want to fill the structure, which is where I need help - I want the result to be:
l_struc:
field_a: "value_a"
field_b: ""
field_c: "value_c"
How can I automatically make the mapping from the name property to the name of the structure component happen and setting its value?

something like:
FIELD-SYMBOLS lv_field TYPE ANY.
LOOP AT itab
ASSIGNING FIELD-SYMBOL(<ls_itab>).
ASSIGN COMPONENT <ls_itab>-name
OF STRUCTURE l_struc
TO <lv_field>.
IF sy-subrc EQ 0.
<lv_field> = <ls_itab>-value.
ENDIF.
ENDLOOP.

Related

cmd_ei_api=>maintain_bapi to update kna1 table field (ICMSTAXPAY)

I have a requirement to update this field ICMSTAXPAY in KNA1 table using my custom report. So, I tried using cmd_ei_api=>maintain_bapi to update the table. But once I run the program, that particular field is not updated and I don't get any error messages too.
My logic:
Read the KNA1 entries.
Edit the required field to my value.
Pass mandatory data to HEADER for update.
Pass my new KNA1 entries to CENTRAL_DATA.
Read data from table:
CALL METHOD cmd_ei_api_memory=>get_global_kna1
EXPORTING
iv_kunnr = <lfs_final>-kunnr
IMPORTING
es_kna1_old = ls_old.
Change the value of field:
ls_old-icmstaxpay = 9.
MOVE-CORRESPONDING ls_old TO ls_customer-central_data-central-data.
Assign header data:
ls_customer-header-object_instance-kunnr = <lfs_final>-kunnr.
ls_customer-header-object_task = 'U'.
Add all the above to the master data structure:
APPEND ls_customer TO lt_customers[].
ls_master_data-customers = lt_customers[].
Pass the data and update to table:
cmd_ei_api=>initialize( ).
LOOP AT lt_customers INTO ls_customer.
cmd_ei_api=>lock( iv_kunnr = ls_customer-header-object_instance-kunnr ).
ENDLOOP.
" Update Customer with CMD_EI_API
CALL METHOD cmd_ei_api=>maintain_bapi
EXPORTING
iv_test_run = space
is_master_data = ls_master_data
IMPORTING
es_message_defective = ls_message_defective.
IF ls_message_defective IS INITIAL.
BREAK-POINT.
COMMIT WORK.
ELSE.
BREAK-POINT.
ENDIF.
LOOP AT lt_customers INTO ls_customer.
cmd_ei_api=>unlock( iv_kunnr = ls_customer-header-object_instance-kunnr ) .
ENDLOOP.
When I debug, I can see that the entry that is being fetched for update is the old entry that is present in the current memory.
Please let me know if i am doing something wrong while passing the value to the table.
You need including DATAX with X for all fields that you need change.
DATA: ls_datax TYPE cmds_ei_vmd_central_data_xflag.
ls_datax-icmstaxpay = 'X'.
MOVE ls_datax TO ls_customer-central_data-central-datax.
And thanx for your question, helped me with find this methody :)

How to assign internal table into a structure and then to a field in 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.

Creating a range for a field from internal table using RTTS

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.

How to update Z fields with BAPI_OUTB_DELIVERY_CHANGE parameter EXTENSION2?

How to update Z fields with BAPI_OUTB_DELIVERY_CHANGE using EXTENSION2?
I tried to update some Z fields in LIKP table using the BAPI to update deliveries but after call it any changes wasn't made.
Any suggestions?
I found the BAdI - SMOD_V50B0001. I made an enhancement implementaction and in the method EXIT_SAPLV50I_010 (User Exit BAPI for Changes to Outbound Delivery) set the follow code.
METHOD if_ex_smod_v50b0001~exit_saplv50i_010.
CONSTANTS: lc_vbkok TYPE char5 VALUE 'VBKOK', "Enhance the structure for more z fields in LIKP
lc_vbpok TYPE char5 VALUE 'VBPOK', "Enhance the structure for more z fields in LIPS
lc_cs_vbkok TYPE char8 VALUE 'CS_VBKOK'.
DATA: lv_item TYPE posnr_vl.
FIELD-SYMBOLS: <lfs_fieldname> TYPE any.
LOOP AT extension2 INTO DATA(lw_extension2).
CASE lw_extension2-param.
"As a structure in row 0
WHEN lc_vbkok. "Fields for LIKP
ASSIGN (lc_cs_vbkok) TO FIELD-SYMBOL(<lfs_vbkok>).
IF <lfs_vbkok> IS ASSIGNED.
ASSIGN COMPONENT lw_extension2-field OF STRUCTURE <lfs_vbkok> TO <lfs_fieldname>.
IF <lfs_fieldname> IS ASSIGNED.
<lfs_fieldname> = lw_extension2-value.
ENDIF.
ENDIF.
"As a table from row 1 to n
WHEN lc_vbpok. "Fields for LIPS
MOVE lw_extension2-row TO lv_item.
READ TABLE ct_vbpok ASSIGNING FIELD-SYMBOL(<lfs_vbpok>) WITH KEY posnr_vl = lv_item.
IF sy-subrc = 0.
ASSIGN COMPONENT lw_extension2-field OF STRUCTURE <lfs_vbpok> TO <lfs_fieldname>.
IF <lfs_fieldname> IS ASSIGNED.
<lfs_fieldname> = lw_extension2-value.
ENDIF.
ENDIF.
ENDCASE.
ENDLOOP.
ENDMETHOD.
Enhace the structures VBKOK as well LIKP with appen structures to add new z fields and enhance the structure VBPOK as well LIPS for the same purpose.
Also take a look to the program LV50LF01 and would need to implement an additional enhancement point to keep the values.
After this a think that I got it.
METHOD m_update_delivery.
DATA: lw_header_data TYPE bapiobdlvhdrchg,
lw_header_control TYPE bapiobdlvhdrctrlchg,
lw_extension2 TYPE bapiext.
DATA: li_extension2 TYPE TABLE OF bapiext,
li_return TYPE TABLE OF bapiret2.
DATA: lv_delivery TYPE bapiobdlvhdrchg-deliv_numb.
lw_header_data-deliv_numb = p_w_output-delivery.
lw_header_control-deliv_numb = p_w_output-delivery.
lv_delivery = p_w_output-delivery.
lw_extension2-param = 'VBKOK'.
lw_extension2-field = 'ZZEXIDV'.
lw_extension2-value = p_w_output-value.
APPEND lw_extension2 TO li_extension2.
" Call BAPI to update delivery
CALL FUNCTION 'BAPI_OUTB_DELIVERY_CHANGE'
EXPORTING
header_data = lw_header_data
header_control = lw_header_control
delivery = lv_delivery
TABLES
extension2 = li_extension2
return = li_return.
READ TABLE li_return INTO DATA(lw_return)
WITH KEY type = c_e.
IF sy-subrc <> 0.
COMMIT WORK AND WAIT.
ENDIF.
ENDMETHOD.
You need to add BAPI_COMMIT after your BAPI function module.

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.)