How to include multiple conditions in a SELECT? - where-clause

I am using 5 Parameters to fetch the details from DB table (mara, makt, marc, mard).
PARAMETERS :number TYPE matnr MATCHCODE OBJECT MAT1 ,
type TYPE MTART MATCHCODE OBJECT H_T134 ,
sector TYPE MBRSH MATCHCODE OBJECT H_T137 ,
group TYPE MATKL MATCHCODE OBJECT H_T023 ,
unit TYPE MEINS MATCHCODE OBJECT H_T006 .
First I tried to fetch data from MARA table using the select query. In that to retrieve the particulare record, I have to use the WHERE condition. But I get confused in the condition part. We can check which parameter has value by using INITIAL condition.
But there is a chanced for 2/3/4/5 parameters to have values. For each case we have to write select query (if so it will lead to performance issue) or is there any way for using dynamic condition part in select query?

You can use SELECT-OPTIONS:
TABLES MARA.
SELECT-OPTIONS:
s_matnr FOR mara-matnr MATCHCODE OBJECT MAT1 ,
s_mtart FOR mara-MTART MATCHCODE OBJECT H_T134 ,
s_mbrsh FOR mara-MBRSH MATCHCODE OBJECT H_T137 ,
s_matkl FOR mara-MATKL MATCHCODE OBJECT H_T023 ,
s_meins FOR mara-MEINS MATCHCODE OBJECT H_T006 .
* [...]
SELECT * FROM MARA where
matnr in s_matnr and
mtart in s_mtart and
mbrsh in s_mbrsh and
matkl in s_matkl and
meins in s_meins.
When you do so, you selection screen will allow multiple values and ranges for the data.
If you need single values like the parameter-command, you must set aditional options for the SELECT-OPTION:
NO INTERVALS to allow only single values
NO-EXTENSION to allow only one value.
OBLIGATORY if an empty value is not allowed (As far I understand your question, you have the opposite situation, so you don't need it).
So your selection is:
SELECT-OPTIONS:
s_matnr FOR mara-matnr NO-EXTENSION NO INTERVALS,
s_mtart FOR mara-MTART NO-EXTENSION NO INTERVALS,
s_mbrsh FOR mara-MBRSH NO-EXTENSION NO INTERVALS,
s_matkl FOR mara-MATKL NO-EXTENSION NO INTERVALS,
s_meins FOR mara-MEINS NO-EXTENSION NO INTERVALS.
Remark:
MARA must be defined as a TABLE if you use SELECT-OPTIONS
Do you really need the MATCHCODE OBJECT? Normally the usage of the FOR already defines the correct matchcode object (via data element/domain).
Disclaimer:
I have no SAP-system available yet, so the code may contain syntax errors. - I will check it tomorrow.

I think the easiest way to do this is to use select-options instead. You can then use the select-option value with the in expression in your query.
That way, when the value is empty, it will automatically be ignored (which won't happen when you use an empty parameter in your query), so you won't have to create a separate WHERE expression for each possible combination. An example:
tables: mara.
select-options number for mara-matnr matchcode object mat1 no-extension no intervals.
select-options type for mara-mtart matchcode object h_t134 no-extension no intervals.
select-options sector for mara-mbrsh matchcode object h_t137 no-extension no intervals.
select-options group for mara-matkl matchcode object h_t023 no-extension no intervals.
select-options unit for mara-meins matchcode object h_t006 no-extension no intervals.
select distinct mara~matnr makt~maktx marc~werks mard~lgort into table ta_materials
from mara
inner join makt on makt~matnr = mara~matnr
inner join marc on marc~matnr = mara~matnr
inner join mard on mard~matnr = mara~matnr
where makt~spras = sy-langu and
mara~matnr in number and
mara~mtart in type and
mara~mbrsh in sector and
mara~matkl in group and
mara~meins in unit
order by mara~matnr.
The no-extension and no intervals options will make the select-option behave like a parameter (more or less) on screen.

Related

Checking against value in a STRING_TABLE in a WHERE clause

I have a procedure with the parameter IT_ATINN:
IMPORTING
REFERENCE(IT_ATINN) TYPE STRING_TABLE
IT_ATINN contains a list of characteristics.
I have the following code:
LOOP AT values_tab INTO DATA(value).
SELECT ( #value-INSTANCE ) AS CUOBJ
FROM IBSYMBOL
WHERE SYMBOL_ID = #value-SYMBOL_ID
AND ATINN ??? "<======== HERE ???
APPENDING TABLE #DATA(ibsymbol_tab).
ENDLOOP.
How can I check if ATINN (in the WHERE clause) is equal to any entry in IT_ATINN?
To achieve what you want (and I assume you want dynamic SELECT fields) you cannot use inline declarations here, both in LOOP and in SELECT:
The structure of the results set must be statically identifiable. The SELECT list and the FROM clause must be specified statically and host variables in the SELECT list must not be generic.
So either you use inline or use dynamics, not both.
Here is the snippet that illustrates Sandra good suggestion:
TYPES: BEGIN OF ty_value_tab,
instance TYPE char18,
symbol_id TYPE id,
END OF ty_value_tab.
DATA: it_atinn TYPE string_table.
DATA: rt_atinn TYPE RANGE OF atinn,
value TYPE ty_value_tab,
values_tab TYPE RANGE OF ty_value_tab,
ibsymbol_tab TYPE TABLE OF ibsymbol.
rt_atinn = VALUE #( FOR value_atinn IN it_atinn ( sign = 'I' option = 'EQ' low = value_atinn ) ).
APPEND VALUE ty_value_tab( instance = 'ATWRT' ) TO values_tab.
LOOP AT values_tab INTO value.
SELECT (value-instance)
FROM ibsymbol
WHERE symbol_id = #value-symbol_id
AND atinn IN #rt_atinn
APPENDING CORRESPONDING FIELDS OF TABLE #ibsymbol_tab.
ENDLOOP.
Overall, it makes no sense select ibsymbol in loop, 'cause it has only 8 fields, so you can easily collect all necessary fields from values_tab and pass them as dynamic fieldstring.
If you wanna use alias CUOBJ for your dynamic field you should add it like this:
LOOP AT values_tab INTO value.
DATA(aliased_value) = value-instance && ` AS cuobj `.
SELECT (aliased_value)
...
Remember, that your alias should exists among ibsymbol fields, otherwise in case of static ibsymbol_tab declaration this statement will throw a short dump.

SQL query does not return data

I am developing a SAP program to obtain information about a reference from the material table (MARA).
First I take certain references and then using a loop I need to make other query for every iteration:
SELECT
MARA~BISMT
FROM mara
WHERE mara~matnr = #ref
INTO #var.
I know that the problem is that the types conflict (mara~matnr is characters and ref is string), how can I convert both to the same type and see the results?
You can also use ABAP string templates instead of conversion exits suggested by mkysoft:
DATA: ref TYPE string VALUE '2'.
ref = |{ CONV matnr( ref ) ALPHA = in }|.
SELECT SINGLE bismt
FROM mara
WHERE matnr = #ref
INTO #DATA(var).
You can use field symbol for dynamic type and CONVERSION_EXIT_ALPHA_INPUT function module for formatting value for db.
TABLES: mara.
DATA: ref TYPE string,
var TYPE string.
FIELD-SYMBOLS: <fs_ref> TYPE any.
ref = '11'.
ASSIGN ('mara-matnr') TO <fs_ref>.
CHECK sy-subrc IS INITIAL.
<fs_ref> = ref.
CALL FUNCTION 'CONVERSION_EXIT_ALPHA_INPUT'
EXPORTING
input = <fs_ref>
IMPORTING
output = <fs_ref>.
SELECT SINGLE mara~bismt
FROM mara
INTO #var
WHERE mara~matnr = #<fs_ref>.

Dynamic language output for structure/internal table

I have a selection screen with select-options where I want to enter several information about materials, for example: material number etc.
The user is also able to enter a language which the output should be in.
If the user chooses english the program shall display an internal table with material number, language, material name in english. If the user enters spanish, I want the output to be in spanish.
What do I have to do in order to define a dynamic structure / table which shows the respective columns dependent on the chosen language?
Thanks for your help
It's highly-dependent on the data structure you are going to show to user, but usually you don't need dynamic structure for this, but rather need to populate data dynamically, i.e. depending on current user language.
For example, material texts are stored in MAKT text table, where texts are stored along with language keys by which they are usually retrieved:
SELECT
a~matnr
a~werks
b~maktx FROM ekpo AS a
INNER JOIN makt AS b
ON b~matnr = a~matnr
AND b~spras = sy-langu
INTO CORRESPONDING FIELDS OF TABLE int_out
WHERE
a~matnr IN s_matnr and
a~werks IN s_werks.
Other descriptions in SAP are usually stored in text tables as well.
More about sy-langu and other system fields is here.
UPDATE: If you really want a dynamic structure with all the languages, see this sample:
DATA: lang TYPE SPRAS.
* language selection
SELECT-OPTIONS: s_lang FOR lang.
SELECT a~matnr, a~werks, b~maktx, b~spras UP TO 5000 ROWS
FROM ekpo AS a
JOIN makt AS b
ON b~matnr = a~matnr
INTO TABLE #DATA(int_out)
WHERE a~werks LIKE '3%'
AND a~matnr LIKE '1%'
AND b~spras IN #s_lang.
*finding unique languages
DATA lt_langs TYPE TABLE OF spras.
lt_langs = VALUE #( ( '' ) ).
LOOP AT int_out ASSIGNING FIELD-SYMBOL(<fs_out>)
GROUP BY ( lang = to_upper( val = <fs_out>-spras ) ) ASCENDING
WITHOUT MEMBERS
ASSIGNING FIELD-SYMBOL(<ls_lang>).
APPEND <ls_lang>-lang TO lt_langs.
ENDLOOP.
DATA :
ls_component TYPE cl_abap_structdescr=>component,
gt_components TYPE cl_abap_structdescr=>component_table.
*adding MATNR column
ls_component-name = 'MATNR'.
ls_component-type ?= cl_abap_datadescr=>describe_by_name( 'matnr' ).
APPEND ls_component TO gt_components.
*Creating dynamic structure with column for every lang
LOOP AT lt_langs ASSIGNING FIELD-SYMBOL(<fs_lang>).
CONDENSE <fs_lang>.
IF <fs_lang> IS NOT INITIAL.
ls_component-name = 'makt_' && <fs_lang>.
ls_component-type ?= cl_abap_datadescr=>describe_by_name( 'maktx' ).
APPEND ls_component TO gt_components.
ENDIF.
ENDLOOP.
* constructing dynamic structure
DATA: gr_struct_typ TYPE REF TO cl_abap_datadescr.
gr_struct_typ ?= cl_abap_structdescr=>create( p_components = gt_components ).
* constructing table from structure
DATA: gr_dyntable_typ TYPE REF TO cl_abap_tabledescr.
gr_dyntable_typ = cl_abap_tabledescr=>create( p_line_type = gr_struct_typ ).
DATA: gt_dyn_table TYPE REF TO data,
gw_dyn_line TYPE REF TO data.
FIELD-SYMBOLS: <gfs_line>,<gfs_line1>,<fs1>,
<gfs_dyn_table> TYPE STANDARD TABLE.
CREATE DATA: gt_dyn_table TYPE HANDLE gr_dyntable_typ,
gt_dyn_table TYPE HANDLE gr_dyntable_typ,
gw_dyn_line TYPE HANDLE gr_struct_typ.
ASSIGN gt_dyn_table->* TO <gfs_dyn_table>.
ASSIGN gw_dyn_line->* TO <gfs_line>.
LOOP AT int_out ASSIGNING <fs_out>.
* checking for duplicated
READ TABLE <gfs_dyn_table> ASSIGNING <gfs_line1> WITH KEY ('MATNR') = <fs_out>-matnr.
IF sy-subrc = 0.
CONTINUE.
ENDIF.
* assigning material number
LOOP AT gt_components ASSIGNING FIELD-SYMBOL(<fs_component>).
IF <fs_component>-name = 'MATNR'.
ASSIGN COMPONENT <fs_component>-name OF STRUCTURE <gfs_line> TO <fs1>.
IF <fs1> IS ASSIGNED.
<fs1> = <fs_out>-matnr.
UNASSIGN <fs1>.
ENDIF.
ENDIF.
* assigning languge-dependent names
READ TABLE int_out WITH KEY matnr = <fs_out>-matnr
spras = <fs_component>-name+5
ASSIGNING FIELD-SYMBOL(<fs_spras>).
IF sy-subrc = 0.
ASSIGN COMPONENT <fs_component>-name OF STRUCTURE <gfs_line> TO <fs1>.
IF <fs1> IS ASSIGNED.
<fs1> = <fs_spras>-maktx.
UNASSIGN <fs1>.
ENDIF.
ENDIF.
ENDLOOP.
APPEND <gfs_line> TO <gfs_dyn_table>.
CLEAR: <gfs_line>.
ENDLOOP.
DATA: l_lang TYPE spras VALUE 'E'.
* showing values in proper language depending on user input
LOOP AT <gfs_dyn_table> ASSIGNING <gfs_line>.
ASSIGN COMPONENT 'makt_' && l_lang OF STRUCTURE <gfs_line> TO <fs1>.
IF <fs1> IS ASSIGNED.
WRITE / <fs1>.
UNASSIGN <fs1>.
ENDIF.
ENDLOOP.

How can I sum up or collect the data on the same field?

Hi ABAP users I would like to ask if what process I can make to COLLECT the data on the same field? all I want to do is to sum up or collect the data in dmbtr that belongs to same date, (date field monat) (werks to plant codes)
it_zfi_vbrp_bseg_1-num3 = it_zfi_vbrp_bseg_1-werks.
it_zfi_vbrp_bseg_1-num2 = it_zfi_vbrp_bseg_1-dmbtr.
COLLECT it_zfi_vbrp_bseg_1.
DELETE ADJACENT DUPLICATES FROM it_zfi_vbrp_bseg_1 COMPARING ALL FIELDS.
Sort it_zfi_vbrp_bseg_1 by werks.
LOOP AT it_zfi_vbrp_bseg_1 into wa_zfi_vbrp_bseg_1 WHERE monat = '01'.
IF wa_zfi_vbrp_bseg_1-werks EQ '4030'.
WRITE:/, AT pos wa_zfi_vbrp_bseg_1-dmbtr.
ENDIF.
ENDLOOP.
Any configuration in my codes guys?
Suppose, you already extended standard bseg table with monat field, then you should do like this:
TYPES: BEGIN OF ty_zfi_vbrp_bseg_1,
werks TYPE bseg-werks,
monat TYPE monat,
dmbtr TYPE bseg-dmbtr,
END OF ty_zfi_vbrp_bseg_1.
DATA: it_zfi_vbrp_bseg_1 TYPE TABLE OF ty_zfi_vbrp_bseg_1,
is_zfi_vbrp_bseg_1 TYPE ty_zfi_vbrp_bseg_1.
SELECT werks, monat, dmbtr
INTO TABLE #DATA(lt_bseg)
FROM bseg
WHERE werks = '4030'.
* summation of months
LOOP AT lt_bseg ASSIGNING FIELD-SYMBOL(<fs_line>).
CLEAR: is_zfi_vbrp_bseg_1.
MOVE-CORRESPONDING <fs_line> TO is_zfi_vbrp_bseg_1.
COLLECT is_zfi_vbrp_bseg_1 INTO it_zfi_vbrp_bseg_1.
ENDLOOP.
* output the results
LOOP AT it_zfi_vbrp_bseg_1 ASSIGNING FIELD-SYMBOL(<zfi_line>).
IF <zfi_line>-werks EQ '4030'.
WRITE: / <zfi_line>-werks, <zfi_line>-monat, <zfi_line>-dmbtr.
ENDIF.
ENDLOOP.
Couple of notes to your incorrect code:
COLLECT doesn't work like single statement and should be executed in loop.
To sum with COLLECT statement you should declare work area so that all non-key fields would be numeric. Key fields (even if it is implicit key) can be of any type, as opposed to what Ray said. N type is also OK.
DELETE ADJACENT DUPLICATES is redundant here, because after COLLECT (which makes summation by primary key) you won't have any dups.
This all comes down to how you define your internal table it_zfi_vbrp_bseg_1
For COLLECT to work, you need to define it with character type keys followed by packed field types:
data: begin of it_zfi_vbrp_bseg_1 occurs 0,
werks type werks,
month(2) type c,
dmbtr type dmbtr,
end of it_zfi_vbrp_bseg_1.
That will work.
This will not:
data: begin of it_zfi_vbrp_bseg_1 occurs 0.
include structure vbrp.
data: monat type monat,
dmbtr type dmbtr,
end of it_zfi_vbrp_bseg.
Read the help on COLLECT and define your summary table accordingly.

What is the difference between like and like line of in ABAP?

I have one doubt. May I know what the difference between LIKE and LIKE LINE OF in ABAP is? I have seen somewhere that while declaring the work area they are declaring.
wa LIKE it_one
wa LIKE LINE OF it_one
LIKE LINE OF means that the variable will be of the table line type.
LIKE means that the variable will be exactly of the same type as the one sitting after this key word.
Example
TYPES: BEGIN OF t_my_example_structure,
my_example_field1 TYPE i,
my_example_field2 TYPE n,
END OF t_my_example_structure.
TYPES tt_my_example_structure TYPE STANDARD TABLE OF t_my_example_structure.
DATA: l_tab_my_example TYPE tt_my_example_structure.
* has structure of row of l_tab_my_example so in this case t_my_example_structure.
DATA: l_str_my_example LIKE LINE OF l_tab_my_example.
* is exactly the same table type as l_tab_my_example so in this case tt_my_example_structure.
DATA: l_tab_like_my_example LIKE l_tab_my_example.
* I use it often for LOOP AT <tab> ASSIGNING <fs>.
FIELD-SYMBOLS: <fs_str_my_example> LIKE LINE OF l_tab_my_example.
Well, the difference is when you pass table into subroutine with USING or TABLES.
In 1st case you will get a table without headerline, thus WA_LIKE will be a table too.
In 2nd case IT_DATA will be a table with headerline: this causes IT_DATA actually means IT_DATA as structure or IT_DATA[] as table, depending on context. Particulary, DATA ... LIKE IT_DATA will refer to headerline, and not entire internal table.
You may check this using a debugger:
DATA T_DATA TYPE STRING_TABLE.
PERFORM TEST_01 USING T_DATA.
PERFORM TEST_02 TABLES T_DATA.
FORM TEST_01 USING IT_DATA TYPE STRING_TABLE.
DATA : WA_LIKE LIKE IT_DATA "This is a Table
, WA_LINE LIKE LINE OF IT_DATA.
BREAK-POINT.
ENDFORM.
FORM TEST_02 TABLES IT_DATA TYPE STRING_TABLE.
DATA : WA_LIKE LIKE IT_DATA "This is a String
, WA_LINE LIKE LINE OF IT_DATA.
BREAK-POINT.
ENDFORM.