How to get rows count of internal table in abap? - 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.

Related

I don't understand how READ TABLE inside LOOP works

In my code I need to iterate inside a loop, and for each iteration in the loop I have to fill in the data whose values ​​are different in certain cells.
Reading the sap documentation I have come to the conclusion that what I need is to use a read table to fill for each iteration into a working area that later I'll treat.
I have declarated the following tables:
it_sap with the content of a join from VBRK and VBRP tables
wa_sap as working area
it_ext with content from an another join from an external database
wa_ext as working area.
This is how my loop looks actually like:
LOOP AT it_sap INTO wa_sap.
wa_sap-tipo_documento = wa_sap-xblnr+2(1). " Linea
tiket = wa_sap-xblnr+9(7).
creationyear = wa_sap-fkdat+0(4).
CALL FUNCTION 'CONVERSION_EXIT_ALPHA_INPUT'
EXPORTING
input = tiket
IMPORTING
output = tiket.
CONCATENATE creationyear '/' wa_sap-vkorg wa_sap-xblnr+7(2) '/' tiket INTO wa_sap-codalb.
"CLEAR position.
CALL FUNCTION 'CONVERSION_EXIT_ALPHA_OUTPUT'
EXPORTING
input = wa_sap-posnr
IMPORTING
output = position.
READ TABLE it_ext INTO wa_ext
WITH KEY codalb = wa_ext-codalb
tipo_documento = wa_ext-tipo_documento.
IF sy-subrc = 0.
wa_sap-import_total = wa_ext-import_total.
wa_sap-import = wa_ext-import.
wa_sap-price = wa_ext-price.
wa_sap-price_total = wa_ext-price_total.
wa_sap-disccount = wa_ext-disccount.
wa_sap-quantity = wa_ext-quantity.
MODIFY it_sap FROM wa_sap.
IF wa_sap-importe_total <> wa_sap-netwr. "AND position = 1 .
APPEND wa_sap TO it_results.
ENDIF.
ENDIF.
ENDLOOP.
How does it work? I understand that by using the conditional sy-subrc = 0 I can see if the previous statement gives true or false but I don't quite understand how it works by using READ instead SELECT steament.
Thank you guys!
LOOP AT iterates over all rows of an internal table.
READ TABLE retrieves at most one row from an internal table.
sy-subrc provides you details about how well the previous statement worked. Its values differ with the statement. In case of READ TABLE, it tells you whether a row was found (= 0) or not (<> 0). The IF sy-subrc = 0 after your READ TABLE thus means "if you found such a row".
It's hard to understand what your code is supposed to do and whether it does that correctly without some helpful sample data. As József Szikszai points out in the comments to your question, the READ TABLE's conditions rely on wa_ext, which is never filled in your sample code, so at first glance this looks like it's not working at all or your sample does not include some initialisation code.

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[].

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.

How do I use the "call transaction 'se11' and skip first screen" to activate the search box in ABAP?

What I am trying to do is use
Set Parameter ID 'DTB' Field 'z*'.
Call Transaction 'SE11' and skip First Screen.
At this point I want to activate the search box and take the results into an internal table. Any thoughts? Or is there a way to use the data base statistics to pull this information faster?
Instead of accessing the tables directly, you may want to use a semi-official API that not only handles the activation state, but also takes permissions into account as well:
DATA: lt_tables TYPE STANDARD TABLE OF rpy_tabl.
FIELD-SYMBOLS: <ls_table> TYPE rpy_tabl.
CALL FUNCTION 'RPY_TABLE_SELECT'
EXPORTING
table_name = 'Z*'
TABLES
tabl_inf_tab = lt_tables
EXCEPTIONS
cancelled = 1
not_found = 2
permission_error = 3
OTHERS = 4.
IF sy-subrc <> 0.
* Implement suitable error handling here
ELSE.
LOOP AT lt_tables ASSIGNING <ls_table>.
CASE <ls_table>-tablclass.
WHEN 'TRANSP'. " Transparent table
* ...
WHEN 'INTTAB'. " Structure
* ...
WHEN 'CLUSTER'. " Cluster table
* ...
WHEN 'POOL'. " Pooled table
* ...
WHEN 'VIEW'. " Generated view structure
* ...
WHEN 'APPEND'. " Append structure
* ...
ENDCASE.
ENDLOOP.
ENDIF.
The code below will get what you want, you might need to add some more where clauses to only get active tables (AS4LOCAL EQ 'A')or only transparent tables (TABCLASS EQ 'TRANSP') since this table also contains structures.
DATA: t_tabname TYPE STANDARD TABLE OF tabname.
SELECT tabname INTO TABLE t_tabname FROM dd02l WHERE tabname LIKE 'Z%'.

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.