Error DBIF_RSQL_INVALID_RSQL CX_SY_OPEN_SQL_DB in program - abap

I get the following error: DBIF_RSQL_INVALID_RSQL CX_SY_OPEN_SQL_DB (Open SQL command is too big. Condition WHERE of the Open SQL command contains too many conditions). The error points to the following line:
select * from Z3T_MAILS into table t_full_mail UP TO 250 ROWS where ID in r_mid and (p_dat_clause).
Other parts of code:
DATA: p_dat_clause type STRING,
t_full_mail type Z3TT_MAILS,
r_mid type range of Z3E_MAIL_ID.
<...>
if not NOT_READED is initial.
p_clause = 'ISREAD = '''''.
endif.
if DATETO is initial.
p_dateto = DATEFROM.
else.
p_dateto = DATETO.
endif.
if not DATEFROM is initial or not DATETO is initial.
concatenate 'SEND_DATE >= ''' DATEFROM ''' and SEND_DATE <= ''' p_dateto '''' into p_dat_clause.
endif.
<...>
if MAILS is supplied or BODY is supplied or p_dat_clause ne ''.
if not r_mid[] is initial.
select * from Z3T_MAILS into table t_full_mail UP TO 250 ROWS where ID in r_mid and (p_dat_clause).
endif.
endif.
I am new to ABAP and would appreciate any help!

That error happens when you use a range/select-option that has too many entries for the database to handle. The solution to this is always dependent on the use, but in any case you have to limit the number of entries in the range.
In your case you only want up to 250 rows from the database anyway. So, if R_MID is filled with all rows containing a single ID you can check the number of lines in it (LINES( R_MID ) ) and limit it to 250 if there are more than that. In most systems this would get rid of the error.

I'm just guessing here but your range r_mid probably has hundreds of lines that look like this:
r_mid-sign = 'I'.
r_mid-option = 'EQ'.
r_mid-low = '123123123'.
r_mid-high = ''.
So instead you could store those IDs in an internal table. You even might be able to use the internal table you're looping over to fill r_mid in the first place.
Your date variables on the other hand are actually well suited to be declared as a single range:
r_date-sign = 'I'.
r_date-option = 'BT'.
r_date-low = datefrom.
r_date-high = dateto.
Also note the documentation about ranges.
Finally you can write your query as follows:
SELECT *
FROM z3t_mails
INTO TABLE t_full_mail
FOR ALL ENTRIES IN lt_mid
WHERE id EQ lt_mid-id
AND send_date IN r_date.

Related

Assigning Field Symbols to Internal Table

I'm trying upload Excel file to internal table in ABAP. I'm using function GUI_UPLOAD and then SCMS_BINARY_TO_XSTRING. At last I have field sybmbol <gt_data> with data from Excel file.
DATA(lo_data_ref) = lo_excel_ref->if_fdt_doc_spreadsheet~get_itab_from_worksheet(
lv_woksheetname ).
*-- Excel work sheet data in dyanmic internal table
ASSIGN lo_data_ref->* TO <gt_data>.
A [CString]
B [CString]
data1
data11
data2
data22
data3
data33
How I can iterate <gt_data> to internal table? I would try like below, but I received dump.
TYPES: BEGIN OF lty_test,
A TYPE string,
B TYPE string,
END OF lty_test.
DATA: lt_test_table TYPE STANDARD TABLE OF lty_test.
As far as I understood, you want to read excel rows with this code.
LOOP AT <gt_data> ASSIGNING FIELD-SYMBOL(<ls_data>).
ENDLOOP.
I am not sure struct of <ls_data> but I think you can read it with index for get to know main idea.
Could you try it like below?
CHECK <gt_data> IS ASSIGNED.
"It's column count for excel file. It can be found dynamically.
DATA(lv_column_count) = 10.
"Loop for rows.
LOOP AT <gt_data> ASSIGNING FIELD-SYMBOL(<ls_data>).
"Loop for columns
DO lv_column_count.
ASSIGN COMPONENT sy-index OF <ls_dat> TO FIELD-SYMBOL(<lfs_value>).
ENDDO.
ENDLOOP.
So first you need to declare a structure for the internal table and each field in the structure should have type "string".
Types:begin of ty_upload,
Field1 type string,
Field2 type string,
End of ty_upload.
Data:it_upload type standard table of ty_upload.
It_upload[] = <gt_data>
Now internal table it_upload should have the data from the field value
Try this:
file = 'C:\xyz.XLS'.
CALL FUNCTION 'ALSM_EXCEL_TO_INTERNAL_TABLE'
EXPORTING
filename = file
i_begin_col = '1'
i_begin_row = '1'
i_end_col = '5'
i_end_row = '6000'
TABLES
intern = xcel
EXCEPTIONS
inconsistent_parameters = 1
upload_ole = 2
OTHERS = 3.
LOOP AT xcel.
" xcel is an internal table and has field xcel-value
ENDLOOP.

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.

Check for duplicated values in the internal table

How can I check the repetitive value in the "Form #" column?
I want to highlight it later as duplicate record.
LOOP AT ZVBELNEXTTAB WHERE werks IN werks.
ZVBELNEXTTAB_COPY-WERKS = ZVBELNEXTTAB-WERKS.
ZVBELNEXTTAB_COPY-MANDT = ZVBELNEXTTAB-MANDT.
ZVBELNEXTTAB_COPY-BUKRS = ZVBELNEXTTAB-BUKRS.
ZVBELNEXTTAB_COPY-VBELN = ZVBELNEXTTAB-VBELN.
ZVBELNEXTTAB_COPY-EVBELN = ZVBELNEXTTAB-EVBELN.
ZVBELNEXTTAB_COPY-FKDAT = ZVBELNEXTTAB-FKDAT.
ZVBELNEXTTAB_COPY-VBLSTAT = ZVBELNEXTTAB-VBLSTAT.
ZVBELNEXTTAB_COPY-ZPRN = ZVBELNEXTTAB-ZPRN.
ZVBELNEXTTAB_COPY-UNAME = ZVBELNEXTTAB-UNAME.
ZVBELNEXTTAB_COPY-TYPE = ZVBELNEXTTAB-TYPE.
curr = ZVBELNEXTTAB-EVBELN.
lv_tab = SY-TABIX + 1.
READ TABLE ZVBELNEXTTAB INDEX lv_tab.
next = ZVBELNEXTTAB-EVBELN.
IF curr GT next.
a = curr - next.
ELSE.
a = next - curr.
ENDIF.
IF a GT 1.
curr = curr + 1.
next = next - 1.
ZVBELNEXTTAB_COPY-MISSINGFROM = curr.
ZVBELNEXTTAB_COPY-MISSINGTO = next.
ELSE.
ZVBELNEXTTAB_COPY-MISSINGFROM = ''.
ZVBELNEXTTAB_COPY-MISSINGTO = ''.
ENDIF.
APPEND ZVBELNEXTTAB_COPY.
SORT ZVBELNEXTTAB_COPY BY EVBELN.
ENDLOOP.
ENDFORM.
I still trying to check the duplicate "Form #" column by using 1 dimensional array by looping them.
Use GROUP BY functionality during looping. You wanna extract duplicates based on comparison fields Company code, Plant, Form #, Sales Doc, Billing date, Username.
So you should write something like this:
TYPES tt_vbeln TYPE STANDARD TABLE OF vbeln WITH DEFAULT KEY.
DATA duplicates TYPE tt_vbeln.
LOOP AT ZVBELNEXTTAB INTO DATA(zvbeln)
GROUP BY ( BUKRS = zvbeln-BUKRS
WERKS = zvbeln-WERKS
VBELN = zvbeln-VBELN
EVBELN = zvbeln-EVBELN
FKDAT = zvbeln-FKDAT
UNAME = zvbeln-UNAME
size = GROUP SIZE )
ASCENDING REFERENCE INTO DATA(group_ref).
CHECK group_ref->*-size > 1. "extracting dups
duplicates = VALUE tt_vbeln( BASE duplicates FOR <form_num> IN GROUP group_ref ( <form_num> ) ).
* setting color
MODIFY duplicates FROM VALUE tt_vbeln( line_color = 'C410' ) TRANSPORTING line_color WHERE line_color IS INITIAL.
ENDLOOP.
That allows you to extract sets of duplicated values like this
By the way, in the above sample rows of blue dataset differ in fields Form # and Username, so my GROUP snippet won't actually work on them. You should adjust grouping fields accordingly, for example leave only VBELN field as grouping field.
Beforehand you should add field line_color to your structure where you will put color codes for duplicates datasets.
Good sample of conditional coloring an ALV resides here.

Count order lines by condition and calculate the percentage to total lines

Experts,
Please let me know how to write the code in ABAP to implement the following logic?
From the below screenshot, for each "S_ORD_ITM", I have to determine if Order_Qty = Dlv_Qty. If yes, determine the total count of S_ORD_ITM for which Order_Qty = Dlv_Qty. In this example, for all 6 rows of S_ORD_ITM, Order_Qty = Dlv_Qty. So, this value would be 6. Lets says this as 'X' Next step is to find the total record count of S_ORD_ITM column. It is also 6 in this case. Lets says this as 'Y'.
My result should be [X/Y]*100.
In some cases, there could be total of 18 S_ORD_ITM, out of which only there exists only 6 records of S_ORD_ITM for which Ord_Qty = Dlv_Qty. So, my result would be [6/18]*100 = 33.33%
This logic has to be implemented for delivery numbers which have a first pass indicator as 'X'. Imagine this sales order has many delivery numbers, and the delivery number in this example is a first pass indicator with 'X'. I already have a loop statement in my end routine, that says
LOOP AT RESULT PACKAGE ASSIGNING RESULT FIELDS WHERE /BIC/FIRSTPASS = 'X'.
Please let me know how I can make use of this already available loop statement and implement the above logic.
Thanks a ton,
G.
UPDATE:
Hello Goutham,
You can solve the whole thing a lot easier. You just need to make a data flow from your DSO where the order data is, then you do a lookup. with that you loop through your result data and push just the extracted, aggregated rows in a new DSO. First build the target structure and the DSO and then use an expert routine / end routine with an abap coding like i described.
END UPDATE
so the Structure is like
sales_order, plant, shipping_point, delivery_number, s_ord_itm, ord_qty, dlv_qty
in your result package variable. is that correct? without a screenshot it is very hard to know what you mean, do you mean a SAP BW transformation or just ABAP code?
you could add some helper-variables to your structure or do it in the loop, i prefer doing it in the loop. but first you have to sort your result package!
your coding should be something like this (pseudo code) where your x variable is v_counter_ord_itm and v_counter_ord_dlv is your y:
make some data definitions like
WA_RESULT.../END OF... (build a workarea for sales_order, result)
T_RESULT (make an itab out of workarea)
WA (workarea with sales_order, counter_ord_itm, counter_ord_dlv)
PSEUDO-CODE!!!
SORT RESULT_PACKAGE BY /BIC/SALES_ORDER
WA-SALES_ORDER = 0.
WA-COUNTER_ORD_ITM = 0
WA-COUNTER_ORD_DLV = 0
LOOP AT RESULT PACKAGE ASSIGNING RESULT FIELDS WHERE /BIC/FIRSTPASS = 'X'.
IF WA-SALES_ORDER NE /BIC/SALES_ORDER.
IF WA-SALES_ORDER NE 0.
WA_RESULT-RESULT = WA-COUNTER_ORD_DLV / WA-COUNTER_ORD_ITM * 100.
WA_RESULT-SALES_ORDER = WA-SALES_ORDER.
APPEND WA_RESULT TO T_RESULT.
CLEAR WA, WA_RESULT.
ENDIF.
WA-SALES_ORDER = /BIC/SALES_ORDER.
ENDIF.
WA-COUNTER_ORD_ITM = WA-COUNTER_ORD_ITM + 1.
IF result_fields-ord_qty EQ result_fields-dlv_qty.
WA-COUNTER_ORD_DLV = WA-COUNTER_ORD_DLV + 1.
ENDIF.
ENDLOOP.
then you have the variables in your itab. for usage within data processing in sap bw, do another loop with a lookup to push the result data in a new field "result" (you have to add it in the output structure):
LOOP AT RESULT_PACKAGE ...
LOOP AT IT_RESULT ASSIGNING <z>
WHERE /BIC/SALES_ORDER = <z>-SALES_ORDER.
RESULT_PACKAGE-RESULT = <z>-RESULT.
ENDLOOP
This is the code that I used:
SELECT doc_number plant ship_point dsdel_date s_ord_item deliv_numb /bic/zlord_qty /bic/zldlv_qty
INTO CORRESPONDING FIELDS OF TABLE it_doc_table
FROM /bic/azord_dso00.
SELECT doc_number COUNT( DISTINCT s_ord_item ) AS numr
FROM /bic/azsd_o11000
INTO CORRESPONDING FIELDS OF TABLE it_count_table
GROUP BY doc_number.
READ TABLE lt_min_flag WITH KEY doc_number = source_fields-doc_number
plant = source_fields-plant
ship_point = source_fields-ship_point
deliv_numb = source_fields-deliv_numb
dsdel_date = source_fields-dsdel_date
INTO lt_min_flag_wa
BINARY SEARCH.
CHECK sy-subrc = 0. CLEAR result.
IT_DOC_TABLE = VALUE /bic/azord_dso00( FOR ls_doc IN it_doc_table WHERE ( doc_number = source_fields-doc_number AND plant = source_fields-plant AND ship_point = source_fields-ship_point AND deliv_numb = source_fields-deliv_numb AND dsdel_date = source_fields-dsdel_date AND /bic/zlord_qty = /bic/zldlv_qty ) ( ls_doc ) ).
z_numr = lines( it_doc_table ).
READ TABLE it_count_table INTO wa_count_table WITH KEY doc_number = source_fields-doc_number.
IF sy-subrc = 0 AND wa_count_table-numr <> 0.
result = ( z_numr / wa_count_table-numr ) * 100 .
ENDIF.

How to get rows count of internal table in abap?

How do I get the row count of an internal table? I guess that I can loop on it. But there must be a saner way.
I don't know if it makes a difference but the code should run on 4.6c version.
There is also a built-in function for this task:
variable = lines( itab_name ).
Just like the "pure" ABAP syntax described by IronGoofy, the function "lines( )" writes the number of lines of table itab_name into the variable.
You can use the following function:
DESCRIBE TABLE <itab-Name> LINES <variable>
After the call, variable contains the number of rows of the internal table .
Beside the recommended
DESCRIBE TABLE <itab-Name> LINES <variable>
there is also the system variable SY-TFILL.
From documentation:
After the statements DESCRIBE TABLE, LOOP AT and READ TABLE, the number of rows of the accessed internal table.
Example script:
REPORT ytest.
DATA pf_exclude TYPE TABLE OF sy-ucomm WITH HEADER LINE.
START-OF-SELECTION.
APPEND '1' TO pf_exclude.
APPEND '2' TO pf_exclude.
APPEND '3' TO pf_exclude.
APPEND '4' TO pf_exclude.
WRITE: / 'sy-tfill = ', sy-tfill.
DESCRIBE TABLE pf_exclude.
WRITE: / 'sy-tfill = ', sy-tfill, 'after describe table'.
sy-tfill = 0. "Reset
READ TABLE pf_exclude INDEX 1 TRANSPORTING NO FIELDS.
WRITE: / 'sy-tfill = ', sy-tfill, 'after read table'.
sy-tfill = 0. "Reset
LOOP AT pf_exclude.
WRITE: / 'sy-tfill = ', sy-tfill, 'in loop with', pf_exclude.
sy-tfill = 0. "Reset
ENDLOOP.
The result:
sy-tfill = 0
sy-tfill = 4 after describe tabl
sy-tfill = 4 after read table
sy-tfill = 4 in loop with 1
sy-tfill = 0 in loop with 2
sy-tfill = 0 in loop with 3
sy-tfill = 0 in loop with 4
Please get attention of the value 0 for the 2nd entry: SY-TFILL is not updated with each step, only after the first loop.
I recommend the usage SY-TFILL only, if you need it direct after the READ(1)... If there are other commands between the READ and the usage of SY-TFILL, there is always the danger of a change of the system variable.
(1) or describe table.
DATA : V_LINES TYPE I. "declare variable
DESCRIBE TABLE <ITAB> LINES V_LINES. "get no of rows
WRITE:/ V_LINES. "display no of rows
Refreance:
http://www.sapnuts.com/courses/core-abap/internal-table-work-area.html
The functional module EM_GET_NUMBER_OF_ENTRIES will also provide the row count. It takes 1 parameter - the table name.
you can also use OPEN Sql to find the number of rows using the COUNT Grouping clause and also there is system field SY-LINCT to count the lines(ROWS) of your table.
if I understand your question correctly, you want to know the row number during a conditional loop over an internal table.
You can use the system variable sy-tabix if you work with internal tables. Please refer to the ABAP documentation if you need more information (especially the chapter on internal table processing).
Example:
LOOP AT itab INTO workarea
WHERE tablefield = value.
WRITE: 'This is row number ', sy-tabix.
ENDLOOP.
data: vcnt(4).
clear vcnt.
LOOP at itab WHERE value = '1'.
add 1 to vcnt.
ENDLOOP.
The answer will be 3. (vcnt = 3).
I don't think there is a SAP parameter for that kind of result. Though the code below will deliver.
LOOP AT intTab.
AT END OF value.
result = sy-tabix.
write result.
ENDAT.
ENDLOOP.