Change field depending on if field value is contained in other table - abap

So my goal is to change a field in a table for those entries that the value is contained in some other table.
So for example.
If the name "John" from table_abc is contained in the table l_t_xyz then change the value to "ABC".
My approach to this:
SELECT * FROM table_xyz INTO TABLE #DATA(l_t_xyz).
Let's say one of the field of table_xyz is NAME.
And i have a second table, also with the field NAME where I want to change one of the fields
LOOP AT table_abc ASSIGNING FIELD-SYMBOL(<abc_line>) WHERE name in table_xyz-name.
<abc_line>-name = 'ABC'
ENDLOOP.
But this gives me an error that table_xyz is a table without a header line, therefore has no component called "NAME".
How do I solve this. Also I can't find any documentation on the keyword IN. Maybe I am using it wrong in this case.

So I have found another solution, which was inspired by Eray answer.
Basing on ranges
SELECT 'I' AS sign,
'EQ' AS option,
name as low
name as high
into table #DATA(range_table)
LOOP AT table_abc[] ASSIGNING FIELD-SYMBOL(<abc_line>) WHERE name in range_table.
<abc_line>-name = 'abc'
ENDLOOP.

You should define a range for name values which stored in table_xyz.
That's quick example:
TYPES lr_name_range_type TYPE RANGE OF name. "you should define appropriate data type
DATA : lr_name_range TYPE lr_name_range_type.
//define macro
DEFINE fill_range.
lr_name_range = VALUE #( BASE lr_name_range( sign = 'I' option = 'EQ' low = &1 ) ).
END-OF-DEFINITION.
//fill range according to table_xyz values
LOOP AT table_xyz ASSIGNING FIELD-SYMBOL(<fs_xyz>).
fill_range <fs_xyz>-name.
ENDLOOP.
//Now you can use IN keyword for your loop
LOOP AT table_abc ASSIGNING FIELD-SYMBOL(<abc_line>) WHERE name in lr_name_range.
<abc_line>-name = 'ABC'
ENDLOOP.

It's faster:
data lt_name type hashed table of table_xyz-name with unique default key.
SELECT * FROM table_xyz INTO TABLE #DATA(l_t_xyz).
lt_name = value #( for group fgv_name of <fs_xyz> in l_t_xyz
group by <fs_xyz>-name
( fgv_name )
).
LOOP AT table_abc ASSIGNING FIELD-SYMBOL(<fs_line>).
if line_exists( lt_name[ table_line = <fs_line>-name ] )
<fs_line>-name = 'ABC'.
endif.
ENDLOOP.

Related

use SELECT on internal table (ABAP)

I am still very inexperienced with SAP ABAP.
I have an internal table that I want to filter further and further based on whether data is present.
I have tried the following, but unfortunately I cannot apply a SELECT to an internal table.
How can I solve this problem?
Hope I have explained my problem clearly enough!
"Here I'm getting the hole database into my internal table
SELECT * FROM TABLE
INTO CORRESPONDING FIELDS OF TABLE #itab.
"This should be my first filter if iv_name is not initial
IF iv_name IS NOT INITIAL.
SELECT * FROM itab
WHERE NAME = #iv_name
INTO CORRESPONDING FIELDS OF TABLE #itab.
ENDIF.
"This should be my second filter if iv_age is not initial
IF iv_age IS NOT INITIAL.
SELECT * FROM itab
WHERE AGE = #iv_age
INTO CORRESPONDING FIELDS OF TABLE #itab.
ENDIF.
There are several ways in ABAP to achieve your goal.
You can use the DELETE keyword to filter the data in an internal table:
IF iv_name IS NOT INITIAL
DELETE itab WHERE name NE iv_name.
ENDIF.
Another possibility is to use the FILTER keyword, but the prerequisite is, that the internal table is TYPE SORTED or HASHED:
itab = FILTER #( itab WHERE name = iv_name ).

A short syntax to fill ABAP table from another table?

In the old ABAP syntax I have to loop over the source table, and inside of the loop append value to the table.
For example:
DATA:
it_source_table type table of mara,
et_result_table type table of matnr.
loop at it_source_table into data(ls_source_table).
append ls_source_table-matnr to et_result_table.
endloop.
Is there with a new ABAP syntax (750, 752) ("move-corresponding", "value#") a way to achieve the same in less sentences?
You can use the VALUE operator with the FOR ... IN addition:
et_result_table = VALUE #( FOR material IN it_source_table ( material-matnr ) ).

Concatenating strings in SAP Query

I'm creating a BAPI for SAP R/3. The equivalent in MSSQL of what I'm trying to write is this:
select
bkpf.BELNR,
bkpf.BUKRS,
bkpf.GJAHR,
bkpf.AWKEY
into
#tab
from
bkpf
where
exists ( select 1 from #n_tab n where CONCAT(n.BELNR, n.GJAHR) = bkpf.AWKEY )
;
But apparently Open Sql doesn't allow operations in queries. So for what I researched, the table I want to "join" must be retrieved to an in memory table, create a new column in a loop doing the operation and the compare with the #tab table. But I'm struggling with the syntax. What I have so far is something like this:
FUNCTION ZBAPI_TEST.
*"----------------------------------------------------------------------
*"*"Local Interface:
*"----------------------------------------------------------------------
select
bkpf~BELNR
bkpf~BUKRS
bkpf~GJAHR
bkpf~AWKEY
into ITAB_BKPF
from bkpf.
loop at ITAB_BKPF.
ITAB_BKPF-chkey = CONCATENATE BELNR GJAHR.
modify ITAB_BKPF.
endloop.
ENDFUNCTION.
But I'm getting the following errors.
Field "ITAB_BKPF" is unknown. It is neither in one of the
specified tables nor defined by a "DATA" statement.
Field "ITAB_BKPF-GJAHR" is unknown. It is neither in one of
the specified tables nor defined by a "DATA" statement.
Incorrect nesting: Before the statement "ENDFUNCTION", the
control structure introduced by "SELECT" must be concluded with
"ENDSELECT".
Incorrect nesting: Before the statement
"+END-OF-INCLUDE", the control structure introduced by "FUNCTION" must
be concluded with "ENDFUNCTION".
There's clearly an open statement. But I'm not really familiar with the language and don't know where the period is required or if I misplaced any closing statement. Other approach I saw online was with a construct SELECT..ENDSELECT:
FUNCTION ZBAPI_TEST.
*"----------------------------------------------------------------------
*"*"Local Interface:
*"----------------------------------------------------------------------
select
bkpf~belnr
bkpf~bukrs
bkpf~gjahr
bkpf~awkey
into corresponding fields
wa_bkpf
from bkpf.
wa_bkpf-chkey = concatenate belnr gjahr.
append wa_bkpf to itab_bkpf.
endselect.
ENDFUNCTION.
But this generate a new batch of errors:
Field "CORRESPONDING" is unknown. It is neither in one of the
specified tables nor defined by a "DATA" statement. Field
"WA_BKPF-CHKEY" is unknown. It is neither in one of the
specified tables nor defined by a "DATA" statement. Field "WA_BKPF"
is unknown. It is neither in one of the specified tables nor defined
by a "DATA" statement.
I suspect the solutions and examples I found online skip some part where they define some of the structures they use. But I don't really know how to do it. Can someone help?
EDIT:
The final code looks like that:
types: begin of t_bkpf,
belnr type belnr_d,
bukrs type bukrs,
gjahr type gjahr,
awkey type awkey,
chkey type string.
types: end of t_bkpf.
data: itab_bkpf type standard table of t_bkpf.
field-symbols: <wa> type t_bkpf.
select
BELNR
BUKRS
GJAHR
AWKEY
into corresponding fields of table ITAB_BKPF
from bkpf.
loop at ITAB_BKPF assigning <wa>.
CONCATENATE <wa>-BELNR <wa>-GJAHR into <wa>-chkey.
endloop.
manoftheyear.
Let me know if this works for you:
*** Definition of custom type.
TYPES: BEGIN OF ty_bkpf,
belnr TYPE bukrs,
bukrs TYPE belnr_d,
gjahr TYPE gjahr,
awkey TYPE awkey,
chkey TYPE string, " Replace with the type you need to use.
END OF ty_bkpf.
*** Definition of internal table of custom type.
DATA lt_bkpf TYPE STANDARD TABLE OF ty_bkpf.
*** Definition of field symbol (pointer) of custom type.
FIELD-SYMBOLS <lfs_bkpf> TYPE ty_bkpf.
*** Extraction of data from BKPF database table.
SELECT belnr bukrs gjahr awkey
FROM bkpf
INTO CORRESPONDING FIELDS OF TABLE lt_bkpf.
*** Checks if extraction was succesful.
IF sy-subrc IS INITIAL.
UNASSIGN <lfs_bkpf>.
*** Loop internal table...
LOOP AT lt_bkpf ASSIGNING <lfs_bkpf>.
*** ...and create value for field CHKEY.
CONCATENATE <lfs_bkpf>-belnr
<lfs_bkpf>-gjahr
INTO <lfs_bkpf>-chkey. " By using a pointer, there's no need to use MODIFY sentence.
ENDLOOP.
ENDIF.
Cheers.
You can use CONCAT directly on QUERY. Example:
SELECT SINGLE CONCAT( CONCAT( a~name1, a~name2 ), a~name3 )
FROM ( ( adrc AS a
INNER JOIN j_1bbranch AS j ON a~addrnumber = j~adrnr )
INNER JOIN t001w AS t ON j~cgc_branch = t~j_1bbranch
AND j~bukrs = #i_postab-bukrs
AND t~werks = #e_postab-prctr+4(4) )
INTO #e_postab-company_name.

How to set dynamic key for READ TABLE?

I'm trying to work out a way to read an internal table that has to be created dynamically. I have created the following report that fills a dynamic internal table with data.
On the last line, I'm trying to read it with a key (mandt for example), but I I get this syntax error:
The specified type has no structure and therefore no component called MANDT
I have debugged and I can see that <any_tab> has been populated successfully and the structure of the table (field names) are correct. The problem presents itself when I try to read the table into a work area. Maybe I'm doing this wrong, but it seems like something that should be possible to do, and I have a feeling I'm missing something small.
The reason I am trying this out is that I have found identical selects happening in a program and want to buffer records in memory and read them from there to avoid DB accesses. This is easy to implement, however I haven't done this when the table, where clause and into clause of the OPEN SQL statement I'm trying to optimize are dynamic.
How to correct the syntax error?
DATA: t681_rep TYPE TABLE OF t681 , wa_681 LIKE LINE OF t681_rep,
tabref TYPE REF TO data , waref TYPE REF TO data.
FIELD-SYMBOLS: <any_tab> TYPE ANY TABLE,
<any_wa> TYPE ANY,
<var1> TYPE ANY.
"fill t681_rep
SELECT *
FROM t681
INTO TABLE t681_rep
UP TO 1 ROWS WHERE kotab = 'A002'.
READ TABLE t681_rep INTO wa_681 WITH KEY kotab = 'A002'.
IF sy-subrc = 0.
"if A002 is found create a table of that type and fill it
CREATE DATA tabref TYPE TABLE OF (wa_681-kotab).
ASSIGN tabref->* TO <any_tab>.
SELECT * UP TO 10 ROWS
FROM (wa_681-kotab)
INTO TABLE <any_tab>.
ENDIF.
CREATE DATA waref TYPE a002.
ASSIGN waref->* TO <any_wa>.
READ TABLE <any_tab> ASSIGNING <any_wa> WITH KEY mandt = '800'. <- problem area
IF sy-subrc = 0.
"do stuff with <any_wa>...
ENDIF.
You just need to put the field name in parentheses.
data: field type string.
field = 'MANDT'.
READ TABLE <any_tab> ASSIGNING <any_wa> WITH KEY (field) = '800'.
IF sy-subrc = 0.
"do stuff with <any_wa>...
ENDIF.
AFAIK, you have to do it the 'long way round':
FIELD-SYMBOLS: <any_field> TYPE any.
LOOP AT <any_tab> ASSIGNING <any_wa>.
ASSIGN COMPONENT 'MANDT' OF STRUCTURE <any_wa> TO <any_field>.
IF <any_field> <> 800.
CONTINUE.
ENDIF.
" do stuff with <any_wa> - you will have to assign <any_field> again to access fields.
ENDLOOP.
You are trying to beat a database in efficiency, it is a loosing battle.
Just go to SE11, select your table, go to technical settings and change the technical settings ( buffering & buffering type ), you do not require an object modification key for this. You can also make sure that the size category is correct.
You can use RTTS to get the table keys.
data table_name type string.
table_name = 'A002'.
" Dynamically create the table type
data the_table type ref to data.
create data the_table type table of (table_name).
" Use RTTS to get table keys
data typedescription type ref to cl_abap_tabledescr.
typedescription ?= cl_abap_tabledescr=>describe_by_data_ref( the_table ).
data keys type abap_table_keydescr_tab.
keys = typedescription->get_keys( ).
REPORT y_test_dynamic_table.
DATA: table_name TYPE string,
typedescription TYPE REF TO cl_abap_tabledescr,
keys TYPE abap_keydescr_tab,
ls_key TYPE abap_keyname.
table_name = 'ZYFRM_STG'.
" Dynamically create the table type
DATA the_table TYPE REF TO data.
CREATE DATA the_table TYPE TABLE OF (table_name).
" Use RTTS to get table keys
typedescription ?= cl_abap_tabledescr=>describe_by_data_ref( the_table ).
keys = typedescription->KEY.
loop at keys INTO ls_key.
***
ENDLOOP.

Error in select no header

I want make select from EPREI to ET_DATA ET_DATA have prices prices is structure what i want fill it from EPREIH...
*"----------------------------------------------------------------------
*"*"Lokálne rozhranie:
*" IMPORTING
*" REFERENCE(I_PREIS) TYPE ZRT_IWP_CPREISTYP OPTIONAL
*" EXPORTING
*" REFERENCE(ET_DATA) TYPE ZTT_IWPIFC_PRICE
*" EXCEPTIONS
*" NO_DATA_SELECTED
*"----------------------------------------------------------------------
field-symbols: <lfs_ET_DATA> like line of ET_DATA.
refresh ET_DATA.
SELECT *
FROM EPREI
into CORRESPONDING FIELDS OF TABLE ET_DATA.
loop at ET_DATA assigning <lfs_ET_DATA>.
select *
from EPREIH
into CORRESPONDING FIELDS OF TABLE ET_DATA-prices
where PREIS = <lfs_ET_DATA>-PREIS
and PREISTYP <= <lfs_ET_DATA>-PREISTYP.
endloop.
it shows error:
"ET_DATA" is table without hedaer line and therefore have not component call prices.
How can i make this select correctly? Sorry for my english but i am so tired...
As the previous answer said, ET_DATA is a reference to a table type and does not have a work area.
So if you really want to add a list of EPREIH into ET_DATA-PRICE you have to point to the work area which is assigned to your field symbol.
Something like this:
field-symbols: <lfs_ET_DATA> like line of ET_DATA.
refresh ET_DATA.
SELECT *
FROM EPREI
into CORRESPONDING FIELDS OF TABLE ET_DATA.
loop at ET_DATA assigning <lfs_ET_DATA>.
select *
from EPREIH
into CORRESPONDING FIELDS OF TABLE <lfs_ET_DATA>-prices
where PREIS = <lfs_ET_DATA>-PREIS
and PREISTYP <= <lfs_ET_DATA>-PREISTYP.
endloop.
extra tip: try using pretty printer with "keywords uppercase" and avoid "select *" if you are not using all fields from those tables.
I'm not entirely sure what you are trying, but it looks like you want to update the field "prices" of table ET_DATA.
If you have 1 record in EPREIH for each record in EPREI, your select should look like this :
loop at ET_DATA assigning <lfs_ET_DATA>.
select single prices
from EPREIH
into <lfs_ET_DATA>-prices
where
PREIS = <lfs_ET_DATA>-PREIS
and PREISTYP <= <lfs_ET_DATA>-PREISTYP.
endloop.
You are using a field (ET_DATA-prices) as a table (INTO CORRESPONDING FIELDS OF). That will not work.
Firstly, the reason you are getting the syntax error is that you would need to update ET_DATA with a work area (structure declared as a line of the same type as the table).
What your code will end up doing though is replacing records in ET_DATA on the second select, on each iteration of your loop, so that will accomplish nothing.
You could most like select everything in one SELECT by using a JOIN:
SELECT E1~FIELD1 E2~FIELD2 (etc.)
FROM EPREI as E1
JOIN EPREIH as E2
ON E2~PREIS = E1~PREIS AND
E2~PREISTYP = E2-PREISTYP
into CORRESPONDING FIELDS OF TABLE ET_DATA.
You will just need to change the field specifications in the SELECT clause above to match the fields in your table (and you could leave out the CORRESPONDING).
And you should probably limit the selection on EPREI with a WHERE clause.