Skip to Content
1

CX_SY_ITAB_DUPLICATE_KEY with VALUE( )

Oct 25, 2016 at 01:05 PM

688

avatar image

Hello,

The exception is raised when i am trying to execute the following code snippet:

TYPES: ty_carrier TYPE HASHED TABLE OF sflight-carrid
       WITH UNIQUE KEY table_line.
DATA: carriers TYPE ty_carrier.
SELECT *
  FROM sflight
  INTO TABLE @DATA(flights).
IF sy-subrc = 0.
  carriers = VALUE #( BASE carriers
    FOR <wa> IN flights ( <wa>-carrid )
  ).
ENDIF.
cl_demo_output=>display_data(
    value = carriers
    name  = |Carriers|    " Name
).

As per the SAP documentation:

"Each inner parenthesis constructs one or more rows in accordance with the information in line_spec and inserts them into the new internal table in accordance with the rules for the statement INSERT ... INTO TABLE."

"lines constructed in line_spec for every iteration of the last FOR expression are inserted into the target table".

My understanding was that with each iteration of the FOR, the lines are inserted. So why is the behaviour differenent when i use the classical approach?

  LOOP AT flights ASSIGNING FIELD-SYMBOL(<flight>).
    INSERT <flight>-carrid INTO TABLE carriers.
  ENDLOOP.

What am i missing here?

BR,

Suhas

10 |10000 characters needed characters left characters exceeded

For me "loop at" is here bugged ;) It should dump as well.

0

That was exactly my first reaction ;)

0

Per SAP documentation:

When single rows are inserted, sy-subrc is set to 4 if a duplicate entry with respect to the primary key were to be produced; also, a handleable exception of the class CX_SY_ITAB_DUPLICATE_KEY is raised if a duplicate entry with respect to a secondary key would were to be produced.

Hence, no dump rather SY-SUBRC is set to 4.

1

When you think of it in detail it's quite a mess, isn't it.

1

I had thought about it, IMO this is because of the legacy ABAP code.

If the behaviour of INSERT...INTO TABLE would have been changed with the introduction of the FOR expression, then suddenly the old code would have started throwing exceptions. Isn't it?

1
* Please Login or Register to Answer, Follow or Comment.

3 Answers

Sandra Rossi Oct 25, 2016 at 06:23 PM
4

I guess the behavior is correct but it's not documented (not yet, maybe tomorrow in 7.51 SP 1 ;-) ) : in old programming, the insertion of one line in a unique index table can be checked with sy-subrc, while a mass insertion leads to exception because it's impossible to handle programmatically this situation. In iteration expressions, it's not possible to handle programmatically (if sy-subrc) a one-line insertion failure, so it's logic that it generates an exception too.

Show 3 Share
10 |10000 characters needed characters left characters exceeded
In iteration expressions, it's not possible to handle programmatically (if sy-subrc) a one-line insertion failure, so it's logic that it generates an exception too.

Agreed.

But how can i resume the processing after the exception has been raised? That means if i want to get the list of unique carriers from the (internal)table of flights, i cannot use the FOR expression? :-|

0

It should be feasible with FOR ... GROUP BY ... I guess that next releases will bring new cool features :)

2

I converted Jānis B's comment at this point into an answer (below).

1
Jānis B Oct 25, 2016 at 08:51 PM
3

Something like this? :)

TYPES: ty_carrier TYPE HASHED TABLE OF sflight-carrid
       WITH UNIQUE KEY table_line.
DATA: carriers TYPE ty_carrier.
SELECT *
  FROM sflight
  INTO TABLE @DATA(flights).
IF sy-subrc = 0.
  carriers = VALUE #( 
    BASE carriers
    FOR GROUPS <gr> of <fs> in flights GROUP BY <fs>-carrid without members
    ( <gr> )
  ).
ENDIF.

cl_demo_output=>display_data(
    value = carriers
    name  = |Carriers|    " Name
).
Show 3 Share
10 |10000 characters needed characters left characters exceeded

And it works, at least for building group key tables :)

0

This is IMO easier to grasp

  carriers = VALUE #( BASE carriers
    FOR GROUPS OF <fs> IN flights
      GROUP BY <fs>-carrid
    ( <fs>-carrid )
  ).
1

Hi Janis, Hi Sandra,

thanks for the solution! Tbh, i did not think about "grouping" the flights by carriers to get the unique carriers.

I use LOOP...GROUP BY regularly, but have not been able to wrap my head around the syntax of the FOR...GROUP BY expression.

Going back to the original question, this means that the behaviour of VALUE...FOR to construct internal tables is not properly documented.

1
Christian Drumm
Oct 25, 2016 at 02:06 PM
1

Hi Suhas,

I think the following is relevant:

"Addition 1

... BASE itab

Effect

... If BASE is specified, the content of itab is assigned to the return value before the individual rows are inserted. If the character # is specified for the type of the return value and the type cannot be determined from the operand position of the constructor expression, the type of itab is used for this expression (if identifiable)."

Sound to my as if lines constructed by FOR are first inserted in a table specified by BASE. This most probably is no hash table and therefore the insert fails. Would be interested to get @Horst Keller's view on this.

Christian


Show 4 Share
10 |10000 characters needed characters left characters exceeded

It's dumping without BASE addition as well :) I'm on 7.40 SP5 here, so no BASE possibility

2

I had given it a shot as well ;)

0

I understand that docu line to mean: before inserting new lines, take over the BASE lines, and the carriers BASE is empty at the beginning anyhow... The debugger after shortdump shows the the first line is inserted, so I assume that the thing is indeed inserting row by row...

1
The debugger after shortdump shows the the first line is inserted, so I assume that the thing is indeed inserting row by row...

You can also set the "Step size" option in the UI-debugger and check that! For the first iteration of the FOR expression the internal table carriers is filled with the first record.

1