‎2005 Dec 20 3:15 AM
Hi all, i was asked to complete another ABAPer's unfinished program. When i did a syntax check and activated it, there was no problem. However, when i ran it, i got a runtime error, called ITAB_DUPLICATE_KEY. The code is as follows:
*&---------------------------------------------------------------------*
*& FORM SEL_REC *
*&---------------------------------------------------------------------*
FORM SEL_REC.
SELECT A~MATNR A~MATKL B~MAKTX *error was marked at this line
INTO TABLE MATPO
FROM MARA AS A
INNER JOIN MAKT AS B
ON A~MATNR = B~MATNR AND
B~SPRAS = 'EN'
INNER JOIN MARD AS C
ON A~MATNR = C~MATNR
WHERE A~MATNR IN I_MATNR AND
A~MATKL IN I_MATKL AND
A~EXTWG IN I_EXTWG AND
C~WERKS = I_WERKS.
LOOP AT MATPO.
SELECT single MAX( A~EBELN ) MAX( A~EBELP ) B~BEDAT B~LIFNR A~MENGE
A~NETPR
INTO (MATPO-EBELN, MATPO-EBELP, MATPO-BEDAT, MATPO-LIFNR,
MATPO-MENGE, MATPO-NETPR)
FROM EKPO AS A
INNER JOIN EKKO AS B
ON B~EBELN = A~EBELN
WHERE A~BSTYP = 'F' AND
A~MATNR = MATPO-MATNR AND
A~WERKS = I_WERKS AND
B~BUKRS = I_BUKRS AND
A~LOEKZ = ' '
GROUP BY B~BEDAT B~LIFNR A~MENGE A~NETPR .
MOVE MATPO-MATNR TO TXT_KEY.
PERFORM READ_TXT USING 'BEST' TXT_KEY 'MATERIAL'.
CONCATENATE MATPO-EBELN MATPO-EBELP INTO TXT_KEY.
PERFORM READ_TXT USING 'F01' TXT_KEY 'EKPO'.
MODIFY MATPO
TRANSPORTING EBELN EBELP BEDAT LIFNR MENGE NETPR
WHERE MATNR = MATPO-MATNR.
ENDLOOP.
ENDFORM.
Can anyone tell me what is the cause behind the error?
‎2005 Dec 20 3:18 AM
How did you define your itab MATPO? You must have defined it with unique key, where as your select can potentially pick up multiple duplicate records because you are going to MARD without full key.
‎2005 Dec 20 3:32 AM
Well, this was how it was originally defined, i'm still looking through the original coding...here goes:
TYPES: BEGIN OF TYP_MATPO,
MATNR LIKE MARA-MATNR, "Material Number
MATKL LIKE MARA-MATKL, "Material Group
MAKTX LIKE MAKT-MAKTX, "Material Description
MENGE LIKE EKPO-MENGE, "Purchase order quantity
NETPR LIKE EKPO-NETPR, "Net price in purchasing document
BEDAT LIKE EKKO-BEDAT, "Purchasing Document Date
LIFNR LIKE EKKO-LIFNR, "Account Number of the Vendor
EBELN LIKE EKKO-EBELN, "Purchasing Document Number
EBELP LIKE EKPO-EBELP, "Item Number of Purchasing Document
END OF TYP_MATPO.
‎2005 Dec 20 3:50 AM
I think you'd be better off eliminating the WHERE MATNR = MATPO-MATNR because you are already looping at the matpo table and you will update the same materials multiple times needlessly. Instead, since you are already looping at the table matpo just move sy-tabix into a variable V_VARIABLE that is defined LIKE SY-TABIX. Do this immediately after the loop at so you get the right sy-tabix value as it will change with other table reads. Then when you do your modify statement replace the WHERE MATNR = MATPO-MATNR with INDEX V_VARIABLE. That should work.
‎2005 Dec 20 3:51 AM
Bernard,
What you have given is only the TYPE declaration not the internal table. There should be a DATA statement where the internal table will be defined.
I am sure it will be defined with a unique key.
Look for the MATPO internal table.
Regards,
Ravi
‎2005 Dec 20 3:53 AM
This is defining your internal table type, but somewhere you must have defined MATPO itself. I want to look at that one.
Srinivas
‎2005 Dec 20 3:53 AM
Hi,
It pasted astructure. Copy and paste the declaration of 'MATPO'. ( It will like : MATPO ..TYP_MATPO ...WITH HEADER LINE )
Thanks
‎2005 Dec 20 3:57 AM
Oh, so that what it does, i was looking at it and i didn't know what it meant 😛
Newbie here, many apologies
DATA: MATPO TYPE HASHED TABLE OF TYP_MATPO
WITH UNIQUE KEY MATNR
WITH HEADER LINE.
Could anyone explain the use of TYPES, why can't i we use TABLES straight away?
‎2005 Dec 20 4:01 AM
DATA: MATPO TYPE HASHED TABLE OF TYP_MATPO
<b> WITH UNIQUE KEY MATNR</b>
WITH HEADER LINE.Yes the highlighted one is what is causing it.
Types are more needed in ABAP objects context. TABLES statement is used only in conjunction with <b>database structures and tables</b><i> not internal tables</i>.
Srinivas
‎2005 Dec 20 4:04 AM
‎2005 Dec 20 4:10 AM
Bernard,
If you are expecting to process the duplicate entries as well, yes you need to remove the same.
However, I am sure there must be a reason why it's been declared that way. Probably there is something wrong with the data selection because of which it is giving duplicate entries.
Quick solution is to remove it and check the output.
Regards,
Ravi
‎2005 Dec 20 4:26 AM
No don't remove it if it is there and you are adding your code on top of it. Remove the MARD select out of your current select and push it into the loop. Since, in your code, you are not looking to do anything with MARD, I suggest you take it out completely. I think what you wanted to do is to see if the material is in a certain plant or not. If that is the case, replace MARD with MARC and it should work.
‎2005 Dec 20 4:28 AM
Hi again, i did as u suggested...i removed it and ran the program. It took a very long while and i got a TIME_OUT runtime error...it also marked a particular line, as follows:
*&---------------------------------------------------------------------*
*& FORM READ_TXT *
*&---------------------------------------------------------------------*
FORM READ_TXT USING ID XNAME OBJ.
DATA: CTR TYPE I,
PO_CTR TYPE I.
CLEAR: TXT. "this line was marked
SELECT SINGLE * FROM STXH CLIENT SPECIFIED
INTO WA_STXH
WHERE MANDT = SY-MANDT AND
TDOBJECT = OBJ AND
TDNAME = XNAME AND
TDID = ID AND
TDSPRAS = SY-LANGU.
IF SY-SUBRC = 0.
REFRESH txt.
CTR = 1.
CALL FUNCTION 'READ_TEXT'
EXPORTING
CLIENT = SY-MANDT
ID = ID
NAME = XNAME
OBJECT = OBJ
LANGUAGE = SY-LANGU
TABLES
LINES = TXT.
LOOP AT TXT.
IF ID = 'BEST'.
MOVE XNAME TO MATTXT-MATNR.
MOVE CTR TO MATTXT-CTRT.
MOVE TXT-TDLINE TO MATTXT-MAT_TXT.
APPEND MATTXT.
ELSEIF ID = 'F01'.
READ TABLE MATTXT WITH KEY MATNR = MATPO-MATNR CTRT = CTR.
IF SY-SUBRC = 0.
MOVE TXT-TDLINE TO MATTXT-PO_TXT.
MODIFY MATTXT TRANSPORTING PO_TXT
WHERE MATNR = MATPO-MATNR.
ELSE.
MOVE MATPO-MATNR TO MATTXT-MATNR.
MOVE CTR TO MATTXT-CTRT.
MOVE TXT-TDLINE TO MATTXT-PO_TXT.
APPEND MATTXT.
ENDIF.
ENDIF.
CTR = CTR + 1.
ENDLOOP.
ENDIF.
SELECT DISTINCT LIFNR NAME1
FROM LFA1
INTO TABLE I_LFA1
FOR ALL ENTRIES IN MATPO
WHERE SPRAS = 'EN' AND
LIFNR = MATPO-LIFNR.
ENDFORM.
‎2005 Dec 20 4:45 AM
Srinivas, i did as you suggested but i'm still using MARD instead of MARC. When i tried running it, it took too long a time, abt 10 minutes has passed, so i had to stop the transaction. Do you want to have a look at the original coding given to me? I still haven't touch it yet by adding any of my own codes...i'm still trying to understand the flow
‎2005 Dec 20 5:28 AM
The code you published tells me that you are selecting records from MARA, MAKT and MARD. While every material selected from MARA has only one corresponding description for a give language in MAKT, the same is not true with MARD. A material can be extended to any number of locations within a particular plant. Since your internal table does not allow multiple entries for the same material, you cannot use it. Using MARC instead of MARD will ensure that for each material you selected from MARA, there is only one or none for the plant I_WERKS in MARC.
It may be timing out for some other reason. What were you asked to change in this program? Is it related to performance or the runtime error you originally got or entirely different reason?
Srinivas
‎2005 Dec 20 5:35 AM
Your timeout error may actually be coming after the selection from MARA, MAKT and MARD. When you are looping at MATPO, you are doing a select from EKPO and EKKO and doing group operation MAX on the columns directly. This will consume lot of time. Also, your join uses lot of fields in the WHERE clause that may be resulting in a sequential search instead of indexed search. Remove your B~BUKRS condition from the where clause and put it after the select statement as follows.
CHECK EKKO-BUKRS = I_BUKRS. If this does not improve the performance significantly, remove the BSTYP from the where clause and do a similar check as BUKRS.
Srinivas
‎2005 Dec 21 1:56 AM
Sorry for the late reply, i had to participate in a key user training session so i couldn't get back on this until now.
Here's what was originally written in the program and i'm suppose to fill up the blanks:
REPORT ZLPUPO03 NO STANDARD PAGE HEADING LINE-SIZE 275 LINE-COUNT 65
MESSAGE-ID Z00.
TABLES: EKKO, "Purchasing Document Header
EKPO, "Purchasing Document Item
MAKT, "Material Descriptions
MARA, "General Material Data
MARD. "Storage Location Data for Material
* LFA1, "Vendor Master (General Section)
* STXH. "STXD SAPscript text file header
TYPES: BEGIN OF TYP_MATPO,
MATNR LIKE MARA-MATNR, "Material Number
MATKL LIKE MARA-MATKL, "Material Group
MAKTX LIKE MAKT-MAKTX, "Material Description
MENGE LIKE EKPO-MENGE, "Purchase order quantity
NETPR LIKE EKPO-NETPR, "Net price in purchasing document
BEDAT LIKE EKKO-BEDAT, "Purchasing Document Date
LIFNR LIKE EKKO-LIFNR, "Account Number of the Vendor
EBELN LIKE EKKO-EBELN, "Purchasing Document Number
EBELP LIKE EKPO-EBELP, "Item Number of Purchasing Document
END OF TYP_MATPO.
DATA: MATPO TYPE HASHED TABLE OF TYP_MATPO
WITH UNIQUE KEY MATNR
WITH HEADER LINE.
TYPES: BEGIN OF TYP_POIN,
EBELN LIKE EKKO-EBELN, "Purchasing Document Number
EBELP LIKE EKPO-EBELP, "Item Number of Purchasing Document
BEDAT LIKE EKKO-BEDAT, "Purchasing Document Date
LIFNR LIKE EKKO-LIFNR, "Account Number of the Vendor
MENGE LIKE EKPO-MENGE, "Purchase order quantity
PEINH LIKE EKPO-PEINH, "Price unit
END OF TYP_POIN.
DATA: POIN TYPE HASHED TABLE OF TYP_POIN
WITH UNIQUE KEY EBELN EBELP
WITH HEADER LINE.
TYPES: BEGIN OF TYP_MATTXT,
MATNR LIKE MARA-MATNR, "Material Number
CTRT TYPE I,
MAT_TXT(80) TYPE C,
PO_TXT(80) TYPE C,
END OF TYP_MATTXT.
DATA: MATTXT TYPE TYP_MATTXT OCCURS 0 WITH HEADER LINE.
TYPES: BEGIN OF TYP_LFA1,
LIFNR LIKE LFA1-LIFNR, "Account Number of Vendor or Creditor
NAME1 LIKE LFA1-NAME1, "Name 1
END OF TYP_LFA1.
DATA: I_LFA1 TYPE HASHED TABLE OF TYP_LFA1
WITH UNIQUE KEY LIFNR
WITH HEADER LINE.
DATA: WA_STXH TYPE STXH,
TXT LIKE TLINE OCCURS 0 WITH HEADER LINE,
TXT_KEY LIKE STXH-TDNAME, "Name
L_PAGE_COUNT(5) TYPE C.
*&---------------------------------------------------------------------*
*& SELECTION-SCREEN *
*&---------------------------------------------------------------------*
SELECTION-SCREEN BEGIN OF BLOCK 1 WITH FRAME TITLE TEXT-001.
PARAMETERS: I_BUKRS LIKE EKKO-BUKRS DEFAULT 'GSPC' OBLIGATORY,
I_WERKS LIKE MARD-WERKS DEFAULT '6000' OBLIGATORY.
SELECT-OPTIONS: I_MATNR FOR MARA-MATNR,
I_MTART FOR MARA-MTART,
I_MATKL FOR MARA-MATKL,
I_EXTWG FOR MARA-EXTWG.
SELECTION-SCREEN END OF BLOCK 1.
*&---------------------------------------------------------------------*
*& START-OF-SELECTION *
*&---------------------------------------------------------------------*
START-OF-SELECTION.
PERFORM INITIALIZE.
PERFORM SEL_REC.
PERFORM WRT_REP.
PERFORM PAGE_COUNT.
*&---------------------------------------------------------------------*
*& FORM INITIALIZE *
*&---------------------------------------------------------------------*
FORM INITIALIZE.
CLEAR: POIN, MATPO.
REFRESH: POIN, MATPO.
ENDFORM.
*&---------------------------------------------------------------------*
*& FORM SEL_REC *
*&---------------------------------------------------------------------*
FORM SEL_REC.
SELECT A~MATNR A~MATKL B~MAKTX
INTO TABLE MATPO
FROM MARA AS A
INNER JOIN MAKT AS B
ON A~MATNR = B~MATNR AND
B~SPRAS = 'EN'
INNER JOIN MARD AS C
ON A~MATNR = C~MATNR
WHERE A~MATNR IN I_MATNR AND
A~MATKL IN I_MATKL AND
A~EXTWG IN I_EXTWG AND
C~WERKS = I_WERKS.
LOOP AT MATPO.
SELECT single MAX( A~EBELN ) MAX( A~EBELP ) B~BEDAT B~LIFNR A~MENGE
A~NETPR
INTO (MATPO-EBELN, MATPO-EBELP, MATPO-BEDAT, MATPO-LIFNR,
MATPO-MENGE, MATPO-NETPR)
FROM EKPO AS A
INNER JOIN EKKO AS B
ON B~EBELN = A~EBELN
INNER JOIN MARD AS C
ON A~MATNR = C~MATNR AND
A~WERKS = C~WERKS
WHERE A~BSTYP = 'F' AND
A~MATNR = MATPO-MATNR AND
A~WERKS = I_WERKS AND
B~BUKRS = I_BUKRS AND
A~LOEKZ = ' '
GROUP BY B~BEDAT B~LIFNR A~MENGE A~NETPR .
MOVE MATPO-MATNR TO TXT_KEY.
PERFORM READ_TXT USING 'BEST' TXT_KEY 'MATERIAL'.
CONCATENATE MATPO-EBELN MATPO-EBELP INTO TXT_KEY.
PERFORM READ_TXT USING 'F01' TXT_KEY 'EKPO'.
MODIFY MATPO
TRANSPORTING EBELN EBELP BEDAT LIFNR MENGE NETPR
WHERE MATNR = MATPO-MATNR.
ENDLOOP.
ENDFORM.
*&---------------------------------------------------------------------*
*& FORM READ_TXT *
*&---------------------------------------------------------------------*
FORM READ_TXT USING ID XNAME OBJ.
DATA: CTR TYPE I,
PO_CTR TYPE I.
CLEAR: TXT.
SELECT SINGLE * FROM STXH CLIENT SPECIFIED
INTO WA_STXH
WHERE MANDT = SY-MANDT AND
TDOBJECT = OBJ AND
TDNAME = XNAME AND
TDID = ID AND
TDSPRAS = SY-LANGU.
IF SY-SUBRC = 0.
REFRESH txt.
CTR = 1.
CALL FUNCTION 'READ_TEXT'
EXPORTING
CLIENT = SY-MANDT
ID = ID
NAME = XNAME
OBJECT = OBJ
LANGUAGE = SY-LANGU
TABLES
LINES = TXT.
LOOP AT TXT.
IF ID = 'BEST'.
MOVE XNAME TO MATTXT-MATNR.
MOVE CTR TO MATTXT-CTRT.
MOVE TXT-TDLINE TO MATTXT-MAT_TXT.
APPEND MATTXT.
ELSEIF ID = 'F01'.
READ TABLE MATTXT WITH KEY MATNR = MATPO-MATNR CTRT = CTR.
IF SY-SUBRC = 0.
MOVE TXT-TDLINE TO MATTXT-PO_TXT.
MODIFY MATTXT TRANSPORTING PO_TXT
WHERE MATNR = MATPO-MATNR.
ELSE.
MOVE MATPO-MATNR TO MATTXT-MATNR.
MOVE CTR TO MATTXT-CTRT.
MOVE TXT-TDLINE TO MATTXT-PO_TXT.
APPEND MATTXT.
ENDIF.
ENDIF.
CTR = CTR + 1.
ENDLOOP.
ENDIF.
SELECT DISTINCT LIFNR NAME1
FROM LFA1
INTO TABLE I_LFA1
FOR ALL ENTRIES IN MATPO
WHERE SPRAS = 'EN' AND
LIFNR = MATPO-LIFNR.
ENDFORM.
*&---------------------------------------------------------------------*
*& FORM WRT_REP *
*&---------------------------------------------------------------------*
FORM WRT_REP.
SORT MATTXT BY MATNR CTRT.
LOOP AT MATPO.
WRITE:/2 MATPO-MATNR(10),
12 MATPO-MATKL,
21 MATPO-MAKTX(30).
* 51 MATPO-.
LOOP AT MATTXT
WHERE MATNR = MATPO-MATNR.
* IF TYP_MATTXT-CTRT = 1.
WRITE: 51 MATTXT-MAT_TXT, MATTXT-PO_TXT.
* ELSE.
* WRITE:/ 51 MATTXT-MAT_TXT, MATTXT-PO_TXT.
* ENDIF.
ENDLOOP.
ENDLOOP.
ENDFORM.
I'm still trying to understand the flow and its logic. What i don't get is why TYPES was used? Was it really necessary to do it in such a way to begin with? No spec doc was provided for this program, so i'm pretty much given instructions verbally. From what i could understand, i am to enable the program to output the following in the report based on certain selection criteria input by the user:
Material Code (MARA-MATNR)
Material Group (MARA-MATKL)
Material Description (MAKT-MAKTX)
Material PO Text (Can't find it)
Item Text/Specification (Can't find it)
Last Purchase Quantity (EKPO-MENGE)
Last Purchase Price (EKPO-PEINH)
Last Purchase Date (EKKO-BEDAT)
Last Purchase Vendor (LFA1-NAME1)
Srinivas, you mentioned something abt doing away with MARD or replacing it with MARC, but won't touch it yet as i'm still looking into it as to why MARD was used by the pervious ABAPer
‎2005 Dec 21 2:02 AM
TYPES are used to replace the older coding style.
Old Code Style.
Data: begin of itab occurs 0,
fld1 type c,
fld2 type c,
end of itab.New Code Style.
Types: begin of ttab,
fld1 type c,
fld2 type c,
end of ttab.
data: itab type table of ttab.
data: wa type ttab.
This is because with ABAP Objects, the OCCURS 0 is not allowed as are header lines. So you must have a work area.
Regards,
Rich Heilman
‎2005 Dec 21 2:12 AM
Heh, thanks Rich, i didn't know that
But i don't quite get last time of your example:
data: wa type ttab.
What is it suppose to represent?
‎2005 Dec 21 2:13 AM
‎2005 Dec 21 2:23 AM
That line represents the work area for the internal table. When you define an internal table using the OCCURS 0, the header line is there automatically. It is suggested by SAP that you no longer use this syntax. Rather you use the TYPE TABLE OF syntax and then define a work area for the internal table. If you are outside of the OO scope, then there is nothing stopping you from using the WITH HEADER LINE extension.
Data: itab type table of ttab WITH HEADER LINE.You need a header line to access the table. So in this case, with a work area you would access the table like this.
Loop at itab INTO WA.
if WA-FLD1 = 'X'.
wa-fld2 = 'X'.
modify itab from wa.
Endif.
ENDLOOP.
If you were using the older syntax, it would be something like this.
Loop at itab.
if itab-FLD1 = 'X'.
itab-fld2 = 'X'.
modify itab.
Endif.
endloop.
Again, the reason for the work area is because OCCURS 0 and WITH HEADER LINE are not supported in ABAP Objects.
Make sense?
Regards,
Rich Heilman
‎2005 Dec 21 2:35 AM
Not really, the older syntax makes more sense to me, maybe because i started learning with it 😛
However, since the program was originally written that way, i might as follow that style and pick it up, still learning, right?
But when you say "LOOP AT ITAB INTO WA"...does it mean i would have to define WA? And is WA a standard name? Or i could use some other name to replace it?
Thanks Rich
‎2005 Dec 21 2:45 AM
Yes, you need to define WA. The naming convention for internal tables is...
Data: IT_ITAB type table of TTAB.
data: wa_ITAB type ttab.I don't really like this, so I usually use something like this.
Data: iAfko type table of afko.
data: xafko type afko.I just like it better.
I would suggest learning the new syntax as it will become importing when learning ABAP objects.
Regards,
Rich Heilman
‎2005 Dec 21 3:08 AM
Thanks Rich,
I'll play around with it so i could understand more on it...
Ok, i removed the B~BUKRS = I_BUKRS and BSTYP = 'F' conditions from the WHERE clause and replaced MARD with MARC, it worked...performance was significantly improved, at least i get to display the results but it still took a while...500+ records 😛
Anyone has any ideas on how to improve the performance further?
‎2005 Dec 21 5:01 AM
Hi Bernard,
Looks like some of my suggestions worked and I already explained that TYPES are used in more ABAP objects context as implicit work area that is provided using BEGIN OF with OCCURS option of an internal table declaration is not allowed in ABAP objects context.
Concentrate on your second select.
Srinivas
‎2005 Dec 22 7:53 AM
Oh, and i also got back to the consultant and mentioned about using MARC instead of MARD, it seems that i need to stick with using MARD. I went through SE11 and did a query and i noticed that the records that are displayed in MARD is more than in MARC...shouldn't it have the same amount records?
‎2005 Dec 21 6:04 AM
Hi,
i gone through ur code the first mistake u made was u defined matpo as type later u had to define it as a int table from that type but i think u didn't and another problem u r facing is a long response time b'coz of the second loop and ur selection criteria.instead of all these just u declare a internal table by using the fields from all the tables and use a single selection criteria to retrive the data.if this is not clear for u.send the code i'll make the modifications.
Regards,
suresh
‎2005 Dec 21 8:44 AM
It's ok...i need to solve it myself...i'm still at the learning process
I won't close the thread yet, i'm still working on it, i'll post question if i have any.
‎2005 Dec 22 7:50 AM
Hi again...i have a question to ask...if you look back at the original codes i posted, there is a subroutine called READ_TXT. Within it, there is a call function 'READ TEXT', so i went into SE37 to find out what is it all about. The thing is that i don't get it, i don't see what the original ABAPer intends to do with it. Couldn't the text be output immediately by doing a WRITE statement?