ALV Grid for In-Line Declaration - abap

How do you display an in-line declared data type in an ALV grid?
eg:
SELECT *
INTO TABLE #DATA(lt_result)
FROM table.
How can the lt_result be displayed in an ALV grid?

Here is a basic example:
DATA: alv TYPE REF TO cl_salv_table.
SELECT *
INTO TABLE #DATA(lt_result)
FROM table.
cl_salv_table=>factory( IMPORTING r_salv_table = alv
CHANGING t_table = lt_result ).
alv->display( ).
You can find other examples using the SALV Object Model in package SALV_OM_OBJECTS.
This is a more modern approach than using 'REUSE_ALV_GRID_DISPLAY' and you will not need to define a field catalog.

You have to do the same thing regardless of how you created lt_result. A select * as in your example will result in lt_result being equal to if you did DATA lt_result type table of tablename
In this case you can send in the name of the structure. But this only works if the structure type is defined in SE11, i.e. if you do a select * without any joins or aliases.
Otherwise you have to create and send in a field catalog with all the fields in lt_result you wish to display.
Example:
SELECT * FROM mara
UP TO 10 ROWS
INTO TABLE #DATA(lt_mara).
CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY'
EXPORTING
i_callback_program = sy-repid
i_structure_name = 'MARA'
* it_fieldcat => use this if i_structure_name is not sufficient
TABLES
t_outtab = lt_mara
EXCEPTIONS
OTHERS = 1.
The same thing applies if you use cl_gui_alv_grid.
Edit: You can fill the field-catalog dynamically like this:
DATA:
lo_t_struct TYPE REF TO cl_abap_tabledescr,
lo_struct TYPE REF TO cl_abap_structdescr.
lo_t_struct ?= cl_abap_tabledescr=>describe_by_data( lt_result ).
lo_struct ?= lo_t_struct->get_table_line_type( ).
LOOP AT lo_struct->components ASSIGNING FIELD-SYMBOL(<comp>).
"Fill a range-table with <comp>-name
ENDLOOP.
Use the range table to get field-descriptions from table dd04t.
Then loop at lo_struct->components again, and fill the field catalog with fieldname and description.
Here you can also add special logic for any given fields.

Related

Sorted table with parameter t_table of cl_salv_table class

If I use the internal table as a standard table the parameter T_TABLE accepts normally,
but when I declare as a sorted table this error happen: "ITUSER" is not type-compatible with formal parameter "T_TABLE".
Can you guys help me identify why this happens?
TABLES: USER_ADDR,USR41.
TYPES: BEGIN OF LINE02_TYPE,
Z_BNAME TYPE USER_ADDR-BNAME,
Z_NAME TYPE USER_ADDR-NAME_FIRST,
Z_LAST TYPE USER_ADDR-NAME_LAST,
Z_TERMI TYPE USR41-TERMINAL,
Z_LASTD TYPE USR41-LOGON_DATE,
Z_KOSTL TYPE USER_ADDR-KOSTL,
END OF LINE02_TYPE.
DATA: ITUSER TYPE SORTED TABLE OF LINE02_TYPE WITH UNIQUE KEY Z_BNAME,
"ITUSER TYPE standard TABLE OF line02_type,
R_TABLE TYPE REF TO CL_SALV_TABLE.
START-OF-SELECTION.
SELECT A~BNAME A~NAME_FIRST A~NAME_LAST B~TERMINAL B~LOGON_DATE A~KOSTL FROM USER_ADDR AS A
LEFT JOIN USR41 AS B ON B~BNAME = A~BNAME
INTO TABLE ITUSER.
CALL METHOD CL_SALV_TABLE=>FACTORY
IMPORTING
R_SALV_TABLE = R_TABLE
CHANGING
T_TABLE = ITUSER.
CALL METHOD R_TABLE->DISPLAY.
Unfortunately I do not see it is documented anywhere but T_TABLE has to be a STANDARD TABLE. If you dig deeper into FACTORY method the T_TABLE parameter is passed to SET_DATA method which requires the table as STANDARD TABLE
try.
r_salv_table->set_data(
changing
t_table = t_table ).
catch cx_salv_no_new_data_allowed. "#EC NO_HANDLER
endtry.
Moreover if you define the parameter as TABLE a STANDARD TABLE is implicitely meant. Here is the reference
As already pointed out, the signature for factory is changing t_table type table.
TABLE is a generic ABAP type which is the old way to say STANDARD TABLE.
This is required since actions you perform via the ALV are reflected on the table itself. When you press the sort button the internal table will also be sorted (hence also changing). So when you get e.g. the double click event, you can safely access my_table[ row ] since it's sorted in the same way as it's displayed to the user.
Such a sorting cannot be represented in HASHED TABLE or SORTED TABLE (sort can be on any column/s).

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

Assigning Inline declared table to Field Symbols

There is an inline-declared table generated from a SELECT statement as below:
SELECT *
INTO TABLE #DATA(lt_result)
FROM scarr.
How can lt_result be assigned to a Field Symbol?
I tried the following way:
FIELD-SYMBOLS: <fs_lt_result> TYPE ANY.
LOOP AT lt_result ASSIGNING <fs_lt_result>.
But I'm not able to call any components in the field symbol inside the loop like:
WRITE / <fs_lt_result>-carrid.
(syntax error: The data object "<FS_LT_RESULT>" does not have a structure and therefore does not have a component called "CARRID".)
Inline declaration of a field symbol for an internal table in an ASSIGN statement and inline declaration of a field symbol for the rows of the table in a LOOP.
LOOP AT <lt_result> ASSIGNING FIELD-SYMBOL(<line>).
...
ENDLOOP.
source: https://help.sap.com/doc/abapdocu_750_index_htm/7.50/en-US/abenfield-symbol_inline.htm
You declared that the field symbol is of unknown type (ANY, i.e. the exact type is known only at run time), so the compiler can't be sure that the mentioned component (CARRID) exists, hence the syntax error.
If you want to mention a component statically, the compiler must be informed of the exact type (what components exist).
For instance, this would work:
SELECT *
INTO TABLE #DATA(lt_result)
FROM scarr.
FIELD-SYMBOLS: <fs_lt_result> TYPE scarr.
LOOP AT lt_result ASSIGNING <fs_lt_result>.
WRITE / <fs_lt_result>-carrid.
ENDLOOP.
Or use the inline declaration of the field symbol as you proposed in your own answer/solution:
LOOP AT lt_result ASSIGNING FIELD-SYMBOL(<fs_lt_result>).
NB: if your internal table had a type decided at run time only, it would be impossible to indicate statically the component name and you'd need to refer to the component dynamically:
ASSIGN COMPONENT ('CARRID') OF STRUCTURE <fs_lt_result> TO FIELD-SYMBOL(<field>).
IF sy-subrc = 0.
WRITE / <field>.
ENDIF.
EXAMPLE:
FIELD SYMBOL : TYPE VBAK.
DATA: ITAB TYPE TABLE OF VBAK .
SELECT * FROM VBAK INTO TABLE ITAB UP TO 10 ROWS.
LOOP AT ITAB ASSIGNING
WRITE : / -VBELN . (WRITE WHICH OUTPUT YOU WANT TO DISPLAY)
ENDLOOP.

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.