How to create a query with primary/secondary language code - abap

Please tell me how to do so:
there is a table MAKT. I have MAKTX in the French language (SPRAS='FR'), but if French language isn't here, then need to display MAKTX in English. How to do it correctly?
IF MAKT-SPRAS='FR'.
SELECT SINGLE MAKT-MAKTX FROM MAKT WHERE SPRAS='FR'.
ELSE.
SELECT SINGLE MAKT-MAKTX FROM MAKT WHERE SPRAS='EN'.
ENDIF.

You can get with order by.
select * from MAKT where SPRAS = 'FR' or SPRAS = 'EN' order by SPRAS descending.
exit.
endselect.

I personally do not recommend using SELECT...EXIT ENDSELECT. with ORDER BY in this case!
Here is a way that is much more concise and gives full control of what you want to do to the database:
DATA: ls_makt TYPE makt.
SELECT SINGLE * FROM makt
INTO ls_makt
WHERE matnr EQ <your-matnr>
AND ( spras EQ 'FR'
OR ( spras EQ 'EN'
AND NOT EXISTS ( SELECT * FROM makt
WHERE matnr EQ <your-matnr>
AND spras EQ 'FR' ) ) ).
This will select your material text in French or in English, but just if the French text does not exist.
EDITED according to the first comment. You were right, ... SINGLE... was missing in the SELECT statement.

You can create a dynamic where clause in ABAP like this.
DATA wherecond TYPE String.
IF MAKT-SPRAS='FR'.
CONCATENATE 'SPRAS = ''' FR '''' INTO wherecond.
ELSE.
CONCATENATE 'SPRAS = ''' EN '''' INTO wherecond.
ENDIF.
SELECT SINGLE MAKT-MAKTX FROM MAKT WHERE (wherecond).

Related

How to make LIKE behave case-insensitive?

I have an importedParameter which I want to search inside of a column in a SELECT.
But for now it is case-sensitive, how can I make it case-insensitive ?
I've tried multiple things: AND LOWER(columnName) LIKE LOWER(#lv_string) or AND columnName LIKE #tst_string COLLATE utf8_general_ci and some other stuff but got this error:
A Boolean expression is required in positions starting with LOWER(Q.
Sample code:
DATA(tst_string) = '%' && importedParamter && '%'.
IF anotherParameter IS NOT INITIAL.
IF importedParamter IS NOT INITIAL.
SELECT * FROM <table1> as p
INNER JOIN <table2> as q on q~column1 = p~column1
WHERE p~column2 = #anotherParameter
AND q~column2 LIKE #tst_string
INTO CORRESPONDING FIELDS OF TABLE #anotherName
ENDIF.
ENDIF.
I believe Regex is your preferred choice: LIKE_REGEXPR:
SELECT *
FROM <table1> as p
INNER JOIN <table2> as q on q~column1 = p~column1
WHERE p~column2 = #anotherParameter
AND like_regexpr( pcre = '\bparam\b', value = q~column2, CASE_SENSITIVE = 'X' ) = '1'
INTO TABLE DATA(#anotherName).
It has CASE_SENSITIVE predicate which respects (or not) the case.
Though this is available only since ABAP 7.55, so on lower releases you are out of the luck.
This code works fine for me:
SELECT *
FROM adrp
WHERE LOWER( name_first ) LIKE 'phi%'
INTO TABLE #DATA(results).
It finds my personal data entry (as well as those of another "Philipp" and of a "Philip"), even though we are all spelled with a capital P.
LIKE LOWER( 'Phi%' ) does not work, but when you can't control the input, then you can convert it to lower case before the select:
DATA(tst_string) = 'Phi%'.
TRANSLATE tst_string TO LOWER CASE.
SELECT *
FROM adrp
WHERE LOWER( name_first ) LIKE #tst_string
INTO TABLE #DATA(results).
Release: 7.54
I am not sure which release specifically allowed functions like LOWER within the WHERE clause. According to the comments, it should work since 7.51.

find duplicates in column and appending to internal table [duplicate]

We all know these excellent ABAP statements which allows finding unique values in one-liner:
it_unique = VALUE #( FOR GROUPS value OF <line> IN it_itab
GROUP BY <line>-field WITHOUT MEMBERS ( value ) ).
But what about extracting duplicates? Can one utilize GROUP BY syntax for that task or, maybe, table comprehensions are more useful here?
The only (though not very elegant) way I found is:
LOOP AT lt_marc ASSIGNING FIELD-SYMBOL(<fs_marc>) GROUP BY ( matnr = <fs_marc>-matnr
werks = <fs_marc>-werks )
ASSIGNING FIELD-SYMBOL(<group>).
members = VALUE #( FOR m IN GROUP <group> ( m ) ).
IF lines( members ) > 1.
"throw error
ENDIF.
ENDLOOP.
Is there more beautiful way of finding duplicates by arbitrary key?
So, I just put it as answer, as we with Florian weren't able to think out something better. If somebody is able to improve it, just do it.
TYPES tt_materials TYPE STANDARD TABLE OF marc WITH DEFAULT KEY.
DATA duplicates TYPE tt_materials.
LOOP AT materials INTO DATA(material)
GROUP BY ( id = material-matnr
status = material-pstat
size = GROUP SIZE )
ASCENDING REFERENCE INTO DATA(group_ref).
CHECK group_ref->*-size > 1.
duplicates = VALUE tt_materials( BASE duplicates FOR <status> IN GROUP group_ref ( <status> ) ).
ENDLOOP.
Given
TYPES: BEGIN OF key_row_type,
matnr TYPE matnr,
werks TYPE werks_d,
END OF key_row_type.
TYPES key_table_type TYPE
STANDARD TABLE OF key_row_type
WITH DEFAULT KEY.
TYPES: BEGIN OF group_row_type,
matnr TYPE matnr,
werks TYPE werks_d,
size TYPE i,
END OF group_row_type.
TYPES group_table_type TYPE
STANDARD TABLE OF group_row_type
WITH DEFAULT KEY.
TYPES tt_materials TYPE STANDARD TABLE OF marc WITH DEFAULT KEY.
DATA(materials) = VALUE tt_materials(
( matnr = '23' werks = 'US' maabc = 'B' )
( matnr = '42' werks = 'DE' maabc = 'A' )
( matnr = '42' werks = 'DE' maabc = 'B' ) ).
When
DATA(duplicates) =
VALUE key_table_type(
FOR key IN VALUE group_table_type(
FOR GROUPS group OF material IN materials
GROUP BY ( matnr = material-matnr
werks = material-werks
size = GROUP SIZE )
WITHOUT MEMBERS ( group ) )
WHERE ( size > 1 )
( matnr = key-matnr
werks = key-werks ) ).
Then
cl_abap_unit_assert=>assert_equals(
act = duplicates
exp = VALUE tt_materials( ( matnr = '42' werks = 'DE') ) ).
Readability of this solution is so bad that you should only ever use it in a method with a revealing name like collect_duplicate_keys.
Also note that the statement's length increases with a growing number of key fields, as the GROUP SIZE addition requires listing the key fields one by one as a list of simple types.
What about the classics? I'm not sure if they are deprecated or so, but my first think is about to create a table clone, DELETE ADJACENT-DUPLICATES on it and then just compare both lines( )...
I'll be eager to read new options.

How to change loop with SELECT in abap to field-symbol

I have a code like this:
i_mahn is a itab.
Data: gt_mahn type table of i_mahn,
gs_result type i_mahn.
LOOP AT gt_mahn into gs_result
SELECT * FROM mhnd
INTO gs_mhnd
WHERE laufd EQ gs_result-laufd
AND laufi EQ gs_result-laufi
AND cpdky EQ gs_result-cpdky
MOVE-CORRESPONDING gs_mhnd TO gs_result.
ENDSELECT.
ENDLOOP.
and I want to change it to a loop with a field symbol but how? I know that the field-symbol only contains the positions of where the information have been but I dont know how to use the field symbol withe the select in this case....
field-symbols: <gs_mahn> like line of gt_mahn
LOOP AT gt_mahn appending <gs_mahn>
SELECT * FROM mhnd
INTO ???
WHERE laufd EQ <gs_mahn>-laufd
AND laufi EQ <gs_mahn>-laufi
AND cpdky EQ <gs_mahn>-cpdky
MOVE-CORRESPONDING ??? TO ???.
ENDSELECT.
ENDLOOP.
field-symbols: <gs_mahn> like line of gt_mahn.
LOOP AT gt_mahn ASSIGNING <gs_mahn>.
SELECT * FROM mhnd INTO gt_mahn
WHERE laufd EQ <gs_mahn>-laufd
AND laufi EQ <gs_mahn>-laufi
AND cpdky EQ <gs_mahn>-cpdky
MOVE-CORRESPONDING <gs_mahn> TO <whatever>.
ENDSELECT.
ENDLOOP.
I really don't know what you are doing, but in my example you can see how to use field-symbols... google might have also known this easily ... https://help.sap.com/doc/abapdocu_750_index_htm/7.50/en-US/abenfield-symbol_inline.htm

How to add new line to itab with VALUE expression

ABAP 7.40 brought us new syntax, I am still figuring it out.
I want to add a new line to the existing table lt_itab. I found a workaround by adding an empty line and figuring out the current length of the table for an update by index, but is there an easier way?
SELECT spfli~carrid, carrname, connid, cityfrom, cityto
FROM scarr
INNER JOIN spfli
ON scarr~carrid = spfli~carrid
WHERE scarr~carrid = #carrier
ORDER BY scarr~carrid
INTO TABLE #DATA(lt_itab).
"How can I simplify the following code part?"
DATA(lv_idx) = lines( lt_itab ).
APPEND INITIAL LINE TO lt_itab.
lt_itab[ lv_idx + 1 ] = VALUE #( carrid = 'UA'
carrname = 'United Airlines'
connid = 941
cityfrom = 'Frankfurt'
cityto = 'San Francisco' ).
It's all in the documentation:
lt_itab = VALUE #( BASE lt_itab ( carrid = ... ) ).
The index logic is pretty ugly, you can easily use the ASSIGNING addition to the APPEND command to get a field symbol to the newly added line. You can then use that field symbol to fill the table entry using the same VALUE construct you are using now.
Or you can do it in one statement:
APPEND VALUE #( ... ) TO lt_itab.

Disable Column in VA01

I have a requirement where I need to disable the full column in Sales Order Line item. Fields are VBAP-ARKTX and VBAP-KDMAT.
I've found the way to disable columns with data in them, but not the whole column.
I used USEREXIT_FIELD_MODIFICATION to achieve this using the following code;
IF sy-TCODE = 'VA02'.
IF screen-name = 'VBAP-KDMAT' .
screen-INPUT = 0.
modify screen.
ENDIF.
ENDIF.
Is there a way to disable the whole column?
Adjusting table control which contains items is the easiest and the most recommended way. It can be done for single user or for group of users.
Otherwise, try to create a screen variant in SHD0. It allows easily hide any column of any table and any field on the screen.
The specific problem I faced was how to disable two fields, but let standard mapped data to be displayed in them.
To cater this requirement I used the following;
Include: MV45AFZZ
User Exit Name: USEREXIT_FIELD_MODIFICATION
Enhancement Name: -Any name you want-
I created an Enhancement and wrote the following code;
"Specify the condition
IF VBAK-VKORG = '1234' AND ( sy-TCODE = 'VA02' OR sy-TCODE = 'VA01' ) AND ( screen-name = 'VBAP-KDMAT' OR screen-name = 'VBAP-ARKTX' ).
screen-input = 0."disable input
MODIFY SCREEN.
DATA: i_tab_mara TYPE TABLE OF MARA WITH HEADER LINE.
DATA: l_maktx TYPE MAKT-MAKTX.
DATA: WA_MARA LIKE LINE OF i_tab_mara.
DATA: i_tab_vbap TYPE TABLE OF VBAP WITH HEADER LINE.
DATA: wa_vbap LIKE LINE OF i_tab_vbap.
IF sy-TCODE = 'VA01' .
SELECT SINGLE * from MARA INTO WA_MARA WHERE MATNR eq VBAP-MATNR.
SELECT MAKTX FROM MAKT INTO l_maktx WHERE MATNR eq VBAP-MATNR.
ENDSELECT.
VBAP-KDMAT = WA_MARA-KDMAT.
VBAP-ARKTX = l_maktx.
MODIFY SCREEN.
ELSEIF sy-TCODE = 'VA02' .
SELECT SINGLE * FROM VBAP INTO WA_VBAP WHERE VBELN eq VBAK-VBELN AND POSNR eq VBAP-POSNR.
IF WA_VBAP-ARKTX eq ''." Check if the fileds are empty, otherwise old data is overwritten
SELECT MAKTX FROM MAKT INTO l_maktx WHERE MATNR eq VBAP-MATNR.
ENDSELECT.
VBAP-ARKTX = l_maktx.
MODIFY SCREEN.
ENDIF.
IF WA_VBAP-KDMAT eq ''." Check if the fileds are empty, otherwise old data is overwritten
SELECT SINGLE * from MARA INTO WA_MARA WHERE MATNR eq VBAP-MATNR.
VBAP-KDMAT = WA_MARA-KDMAT.
MODIFY SCREEN.
ENDIF.
ENDIF.
ENDIF.
There is one thing, that You can do in the dynpro-designer. There You can modify the sap-standard-dynpro as a dynpro-modification.
Nevertheless, this might be overwritten with the next release. Is this also an option for You ?