Calculate Sum based on condition [duplicate] - sum

This question already has an answer here:
loop with condition ignored by the system in sap abap
(1 answer)
Closed 7 months ago.
How to do summation in the internal table with condition?
For example, my itab have the following data:
itab l_bcode_i :
vgpos[1] :10 , menge[1]:600
vgpos[2] :10 , menge[2]:500
vgpos[3] :20 , menge[3]:400
vgpos[4] :20 , menge[4]:300
vgpos[5] :30 , menge[5]:200
vgpos[6] :30 , menge[6]:10
The requirement request to sum up the data with the same vgpos number by using the menge, and use to display another message.
I try to show
vgpos: 10 menge = 1100
vgpos:20 menge = 500
vgpos:30 menge = 210
I try to use loop and sum, however the result not as the result I need because it will total up all the menge value by ignored the where clause condition that I set. Any recommendation or suggestion is appreciated:
at last, it should menge = 1810
LOOP AT LT_BCODE_I INTO LT_BCODE_I WHERE VGPOS = LW_LIPS2-VGPOS.
AT LAST.
SUM.
cl_demo_output=>display( LT_BCODE_I-MENGE ).
ENDAT.
ENDLOOP.

SUM statement calculates the sum of Numeric Components(Numeric data types). Check and validate the data type for the field MENGE.
Read the documentation about SUM statement,
Also, there is the condition on the LOOP. So, loop executes only once, if VGPOS is considered as key.

Hi I able to fixed my problem by using the following code:
In stead of At Last, I change to use the AT END. After used the AT END, I able to get the result I need.
LOOP AT LT_BCODE_I INTO LT_BCODE_I WHERE VGBEL = LT_LIPS-VGBEL AND VGPOS = LT_LIPS-VGPOS.
AT END OF VGBEL.
SUM.
LT_BCODE_I-MENGE = LT_BCODE_I-MENGE .
ENDAT.
ENDLOOP.

You can find examples in the documentation of SUM.
Here is an excerpt for "Calculation of a sum with SUM at AT END OF. The lines of the respective current group level are evaluated":
DATA:
BEGIN OF wa,
col1 TYPE i,
col2 TYPE i,
END OF wa,
itab LIKE TABLE OF wa WITH EMPTY KEY.
itab = VALUE #( FOR i = 1 UNTIL i > 5
FOR j = 1 UNTIL j > i
( col1 = i col2 = j ) ).
LOOP AT itab INTO wa.
AT END OF col1.
SUM.
cl_demo_output=>write( wa ).
ENDAT.
ENDLOOP.
cl_demo_output=>display( wa ).

Related

Counting Duplicate Row in internal table

I need to count the number of duplicate rows in an internal table base on one field.
I have tried to create a work area and counting the duplicate data but the problem is it counts all duplicate data. My purpose is to count duplicate data by the same date.
DATA: gv_line TYPE i.
gv_line = 0.
LOOP AT i_sect_proe.
IF wa_sect_proe IS INITIAL.
wa_sect_proe = i_sect_proe.
CONTINUE.
ENDIF.
IF wa_sect_proe-/smr/wondat EQ i_final_f-/smr/wondat.
gv_line = gv_line + 1.
ENDIF.
i_sect_proe-/smr/line = gv_line.
ENDLOOP.
The code I've tried displays the number off all duplicate data.
DATA: BEGIN OF lt_result OCCURS 0,               date TYPE datum,               count TYPE i,           END OF lt_result.
SORT yourTable BY dateField.
LOOP AT yourTable.
    lt_result-date   = yourTable-dateField.
    lt_result-count = 1.
    COLLECT lt_result INTO lt_result.
ENDLOOP.
Result in lt_result[].

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.

Error DBIF_RSQL_INVALID_RSQL CX_SY_OPEN_SQL_DB in program

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.

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.