Technical Articles
‘TAB_DUPLICATE_KEY’ issue during Delivery Due for STO
First of all, please notice that it may not easy to catch up without encounter this issue which is an extremely rare scenario. You can skip to the conclusion at the bottom.
Related Notes 1864606
SAP released notes 1864606 to deal with the ‘ITAB_DUPLICATE_KEY’ issue in function group ME06.
SymptomWhen you execute transaction MB5T you receive a program termination of type ITAB_DUPLICATE_KEY in program SAPLME06.Other TermsMB5T, \FUNCTION-POOL=ME06\CLASS=LCL_DB}\DATA=MT_DATA, PRIMARY_KEY, ARRAY_READ EKPVReason and PrerequisitesThis issue is caused by a program error.SolutionImplement attached program correction.
*--------------------------------------------------------------------*
* Read shipping data by using array operation
*--------------------------------------------------------------------*
METHOD array_read.
* define local types
TYPES:
lty_t_input TYPE SORTED TABLE OF ekpo_key
WITH UNIQUE KEY ebeln ebelp.
* define local data objects
DATA: lx_raise TYPE REF TO lcx_raise,
ls_input TYPE ekpo_key,
lt_input TYPE lty_t_input,
lt_array TYPE STANDARD TABLE OF ekpo_key WITH DEFAULT KEY,
lt_data TYPE me->lif_types~type_t_ekpv.
FIELD-SYMBOLS:
<ls_array> TYPE ekpo_key,
<ls_data> TYPE ekpv.
*
* if there are more than 5,000 entries -> refresh and start fresh
IF lines( me->mt_data ) GE me->mc_max.
* Stelle sicher, dass nur das noetigste von der DB-gelesen wird
me->reset( ).
INSERT LINES OF it_array INTO TABLE lt_input.
SELECT * FROM ekpv
INTO TABLE me->mt_data
FOR ALL ENTRIES IN lt_input "1864606
WHERE ebeln = lt_input-ebeln
AND ebelp = lt_input-ebelp.
IF sy-subrc GT 0 OR lines( me->mt_data ) EQ 0.
RAISE EXCEPTION TYPE lcx_raise.
ENDIF.
et_data = me->mt_data.
* mix up existing with new information
ELSE.
LOOP AT it_array ASSIGNING <ls_array>.
READ TABLE me->mt_data
WITH TABLE KEY ebeln = <ls_array>-ebeln
ebelp = <ls_array>-ebelp
ASSIGNING <ls_data>.
IF sy-subrc EQ 0.
IF et_data IS SUPPLIED.
READ TABLE et_data WITH TABLE KEY ebeln = <ls_array>-ebeln
ebelp = <ls_array>-ebelp
TRANSPORTING NO FIELDS.
CHECK sy-subrc GT 0.
INSERT <ls_data> INTO TABLE et_data.
ENDIF.
ELSE.
READ TABLE lt_input WITH KEY ebeln = <ls_array>-ebeln
TRANSPORTING NO FIELDS.
CHECK sy-subrc GT 0.
ls_input-ebeln = <ls_array>-ebeln.
ls_input-ebelp = <ls_array>-ebelp. "1902763
INSERT ls_input INTO TABLE lt_input.
ENDIF.
ENDLOOP.
* Lese Rest von der DB.
IF lines( lt_input ) GE 1.
SELECT * FROM ekpv
INTO TABLE lt_data
FOR ALL ENTRIES IN lt_input
WHERE ebeln = lt_input-ebeln.
IF sy-subrc EQ 0.
* first interation cycle
IF me->mv_iter IS INITIAL. "1864606
INSERT LINES OF lt_data INTO TABLE me->mt_data.
ELSE.
LOOP AT lt_data ASSIGNING <ls_data>. "1864606
READ TABLE me->mt_data WITH TABLE KEY ebeln = <ls_data>-ebeln
ebelp = <ls_data>-ebelp
TRANSPORTING NO FIELDS.
CHECK sy-subrc GT 0.
INSERT <ls_data> INTO TABLE me->mt_data.
ENDLOOP.
ENDIF.
* do array read only up to 2 interation cycles
IF et_data IS SUPPLIED AND me->mv_iter LE 1. "1864606
TRY.
lt_array = lt_input.
me->mv_iter = me->mv_iter + 1.
me->array_read( EXPORTING it_array = lt_array "1864606
IMPORTING et_data = et_data ).
CATCH lcx_raise INTO lx_raise.
CLEAR et_data.
RAISE EXCEPTION lx_raise.
ENDTRY.
ENDIF.
ELSE.
RAISE EXCEPTION TYPE lcx_raise.
ENDIF.
ENDIF.
ENDIF.
ENDMETHOD. "array_read
Dump analysis
* first interation cycle
IF me->mv_iter IS INITIAL. "1864606
INSERT LINES OF lt_data INTO TABLE me->mt_data. "<<<<<<======DUMP LINE
ELSE.
LOOP AT lt_data ASSIGNING <ls_data>. "1864606
READ TABLE me->mt_data WITH TABLE KEY ebeln = <ls_data>-ebeln
ebelp = <ls_data>-ebelp
TRANSPORTING NO FIELDS.
CHECK sy-subrc GT 0.
INSERT <ls_data> INTO TABLE me->mt_data.
ENDLOOP.
ENDIF.
1, First call for all due delivery including all STO
Pay attention to the stack flow and difference compared with the 3rd time.

- it_array: contains all the STO order and item numbers due for delivery
- lt_input: comes from it_array by only the first item per STO order! (watch out only 1 item has been inserted per STO)
- lt_data: fetched from table EKPV by lt_Input without filter item number!
- me->mt_data: store entry from lt_data.

2, Second iteration cycle for all due delivery
The stack will be the same as the first cycle, but the result of lt_array replaced by 1st round lt_input then became the lt_input for 2nd cycle as this method call itself!

METHOD reset.
CLEAR: me->mt_data, me->mv_iter. "1864606
ENDMETHOD. "reset
We get all entries from lt_input (one order with only one item) and fetched again from EKPV which has much fewer results compared to 1st run for me->mt_data (6000+), as this select using EBELP as a filter!
me->reset( ).
INSERT LINES OF it_array INTO TABLE lt_input.
SELECT * FROM ekpv
INTO TABLE me->mt_data
FOR ALL ENTRIES IN lt_input "1864606
WHERE ebeln = lt_input-ebeln
AND ebelp = lt_input-ebelp.
3, Third call of method ‘array_read’ per delivery which haven’t been created yet for STO
The above 2 rounds call of ‘array_read’ is performed for all STO as a whole! When comes to the 3rd call, all due-to delivery data has already been fully prepared include delivery number but has not been submitting&commit so there do not exist physically yet.
* Lese Rest von der DB.
IF lines( lt_input ) GE 1.
SELECT * FROM ekpv
INTO TABLE lt_data
FOR ALL ENTRIES IN lt_input
WHERE ebeln = lt_input-ebeln.
IF sy-subrc EQ 0.
* first interation cycle
IF me->mv_iter IS INITIAL. "1864606
INSERT LINES OF lt_data INTO TABLE me->mt_data.
I know it’s little chaos and confusion to catch up with but couldn’t figure out a better way to explain from a technical point of view unless debugging with me as it’s extremely rare : P
The due delivery program will be called daily for a specific site/plant to generate delivery. It could be set as a background job that runs more frequently like twice even more per day. So very few cases users have a big backlog of delivery due specific for STO which Shipping Data for Stock Transfer of Purchasing Document Item entries more than 5000!
Just imagine how scary the number is, it means 5000 PO items are transferring between two different plants intra-company (not for customers) in less than one day. (It’s not 5000 pieces of 1 PO item!) Yes, it could be a general number for a giant company like Amazon but if that really happens then the inputs of RVV50R10C will be an inappropriate setting.
Conclusion
After finishing this dump analysis and go back to check the related STO at the system. (Get the STO list by it_array at beginning of array_read in 1st call.) Finally, the secret is revealed. Let me try to wrap up the whole story from a business point of view:
- Some STO has been created/changed by some background program. The items number of one STO reach 1500+. Besides, many of them are duplicated items and many of them are marked deleted~ no idea why~
- Even only one item of a specific STO is due to delivery, its whole result list fetched from EKPV will be selected according to STO number after implement notes 1864606. The entry for internal table me->mt_data will be easily reached 5000 with few STOs like the below one. Normal order due to delivery will not trigger this EKPV fetch unless mixed with STO due to delivery, of cause it’ll impact the number of lt_array.
- Once the limit of 5000 is reached, the refresh logic is not considering in full-scale from my point of view, especially in those places which lead to duplicated key insertion.
Options to skip this issue:
- Change code at include program LME06I01 which is not recommended and will be rejected as well~
- Just like some giant trucks stuck the whole road, all the rest cars keep waiting and dumped along with them. Let those giant STO orders due to delivery been processed separately which will skip the logic of reach up-limit. Hopefully, no impact on the delivery priority which is another issue 😀
Please kindly let me know if some incorrect or any better approaches.
Following