Is there a way to retrieve the relative position of a line in an internal table from a reference to that line ? The table line is not unique.
I need to keep track of the positions of the lines of a table after the table is sorted, or if lines are inserted in the middle.
5
You CANNOT DECENTLY retrieve the position of an internal table line from a reference to that line. A reference just points to the memory, it doesn’t know the internal table management information.
By “cannot decently”, I mean that it’s not decent to use the workaround by looping at all the lines of the internal table (slow) and compare their references till you find the right line.
A reference to a line always points to the same line after a table is sorted and modified. I can’t confirm it’s “guaranteed” because it’s not clearly stated in the ABAP documentation, but no doubt for me that it is because the logical order is stored in a separate index, as explained in itab – Line-Based Administration Costs:
“[…] additional memory is required for administrating each individual line, so allowing optimized access to the individual lines. This internal administration of individual lines has two variants:“
- “A table index administrates the logical order of table lines. The additional memory requirement is 6 bytes per table line on average. Exception: If the logical order matches the physical order in the table body, no additional memory is required for the index.“
- “Hash administration […]“
An example confirms what happens after SORT
.
Also, the Data References chapter says that they can point to lines of internal tables without mention of restrictions concerning SORT
or whatever:
“Data references can point to any data objects or to their parts (components, lines of internal tables, or subareas determined by offset or length specifications).“
2
You could do it by using
READ TABLE itab FROM structure_of_itab_type TRANSPORTING NO FIELDS.
and then directly after, you check sy-tabix.
this works even if the reference is not a fieldsymbol, however it olnly finds the first occurence.
If it is Fine for you to only find the first occurence, or your itab lines are always unique, this solution is by my knowledge the most performant.
you can see the code in action.
I made an example here:
REPORT zzyour_name_test.
DATA lt_itab type STANDARD TABLE OF mara.
FIELD-SYMBOLS <ls_mara_line> TYPE mara.
SELECT * FROM MARA INTO TABLE @lt_itab UP TO 20 ROWS.
ASSIGN lt_itab[ 10 ] TO <ls_mara_line>. " assign ref
"now to find line ->
Read table lt_itab FROM <ls_mara_line> TRANSPORTING NO FIELDS.
Data(lv_row) = sy-tabix. "-> 10
BREAK-POINT.
"teset with single field non unique table:
DATA lt_itab2 TYPE STANDARD TABLE OF char20.
APPEND 'test1' TO lt_itab2.
APPEND 'test1' TO lt_itab2.
APPEND 'test1' TO lt_itab2.
APPEND 'test1' TO lt_itab2.
APPEND 'test2' TO lt_itab2.
APPEND 'test3' TO lt_itab2.
APPEND 'test4' TO lt_itab2.
FIELD-SYMBOLS <ls_itab_line> LIKE LINE OF lt_itab2.
ASSIGN lt_itab2[ 2 ] TO <ls_itab_line>. " assign ref
"try again.
Read table lt_itab2 FROM <ls_itab_line> TRANSPORTING NO FIELDS.
Data(lv_row2) = sy-tabix. "-> finds 1 -> it is the firs occurence
BREAK-POINT.
So to say, there is a decent solution, With the only Problem, that it might lead to issues if the ITAB is non-unique
Though for your case there might be a workaround:
"there is this janky fix though ->
Data(ls_copy) = <ls_itab_line>.
<ls_itab_line> = CONV #( cl_system_uuid=>if_system_uuid_rfc4122_static~create_uuid_c36_by_version( version = 4 ) ).
"any value would do as long as it is unique also any field will do ;)
"SET the line we want to check to a unique value.
Read table lt_itab2 FROM <ls_itab_line> TRANSPORTING NO FIELDS.
Data(lv_row3) = sy-tabix. "NOW we changed the line, it can now be found.
BREAK-POINT.
"set the value back ...
<ls_itab_line> = ls_copy.
the workaround has only one setback, If you cannot guarantee a unique value, e.g. if the field is char2 and any value is to be expected, you will not find one unique value, you could fix that, by checking first if the a random value Exists already in the Itab, if not, then use that.
also here is a second image for the workaound:
hope this solves your Problem in a better way 🙂
1