7.4 Release News - Table Expressions


Overview

I hope, you are also satisfied with the new features of the 7.4 Release, you could have try out the different Inline Declarations (DATA or FIELD-SYMBOL), or you got the feeling of using the VALUE and NEW Constructor Expressions.

Today, we will deep dive into another topic, named Table Expressions. We can think of the table expressions as the short form for the READ TABLE statement.

All I can say is, that I was very happy, when I first heard about table expressions, because I just worked on a complex XML parser ABAP program, that used Simple Transformation to parse a really deep and complex XML structure. I made good use of the table expression, when I had to expand the deep structure into a simple flat structure.

So, what are the table expressions?


READ TABLE vs. Table Expressions

Alright, first let's see a typical code snippet for the READ TABLE statement. The old form looks like this: we read a line from the table, flight_schedules into the work area, flight_schedule that has 'AA' Carrier ID and '0017' Connection ID!

Using table expressions, we are able to implement this logic in a more intuitive, compact, and readable way!

" old version
READ TABLE flight_schedules INTO DATA(flight_schedule)
  WITH KEY carrid = 'AA'
           connid = '0017'.

" new version
DATA(flight_schedule) = flight_schedules[ carrid = 'AA' connid = '0017' ].

Another use case is, when we want to look for by table index, using this form: READ TABLE ... INTO ... INDEX i.

I think, this code speaks for itself! GIVE ME THE FIRST ROW OF THE INTERNAL TABLE! Although we lose the semantic meaning with removing the talkative keywords (READ TABLE, INTO, INDEX, ...), I think the 2nd form is much more intuitive, since it's more compact, and we all still associate the [] brackets with the table index look up!

" old version
READ TABLE flight_schedules INTO DATA(first_flight_schedule) INDEX 1.

" new version
DATA(first_flight_schedule) = flight_schedules[ 1 ].


Using Component Selector in Table Expressions

7.4 syntax enables us to go further, and chain a component selector to the table expressions, in order to make our code thinner. In the new version, we are able to access the structure components directly after the table expressions.

" old version
READ TABLE flight_schedules INTO DATA(first_flight_schedule) INDEX 1.
IF first_flight_schedule-cityfrom = 'NEW YORK'.
  ...
ENDIF.

" new version
IF flight_schedules[ 1 ]-cityfrom = 'NEW YORK'.
  ...
ENDIF.

Using table expressions, we are able to do crazy things also, like modifying a structure element: first we determine a specific row, than using the component selector, we modify its component, called cityto

Of course, if our expression does not uniquely define a row, then like the READ TABLE statement, will find and modify only the first occurrence.

" old version
READ TABLE flight_schedules INTO DATA(flight_schedule)
  WITH KEY carrid = 'AA'
           connid = '0017'.

flight_schedule-cityto = 'BUDAPEST'.

" new version
flight_schedules[ carrid = 'AA' connid = '0017' ]-cityto = 'BUDAPEST'.


Chaining Table Expressions

Is it still not enough for you? :)

Alright, let's say we have an internal table, called customers, that actually based on a deep structure. First, we look up for the customer with the ID, '00017'. Then, we want his/her billing address from his/her addresses (the billing address is the first in the address table). At last, we modify the ZIP code in his/her billing address.

In the new version, instead we simply say this: modify the ZIP code of the first address (billing address) of the customer with the ID, '00017'. The point is, in 7.4, we are able to chain many table expressions together, if we want to read a deep structure, for example.

" old version
READ TABLE customers INTO DATA(customer) WITH KEY id = '00017'.
  READ TABLE customer-addresses INTO DATA(billing_address) INDEX 1.
    billing_address-zip_code = 'NH32211'.

" new version
customers[ id = '00017' ]-addresses[ 1 ]-zip_code = 'NH32211'.

I know, it can sound insane, but there are cases when it can be very useful, and effective. Have you ever been used it? Would you use it?


Handling Exceptions

If you take care of the details, you might have observed, that I haven't used any exception handling code yet. The reason is, that I didn't want to overload you with this unnecessarily, but now it's time to talk about it.

In 7.4 if the specified row is not found then, a CX_SY_ITAB_LINE_NOT_FOUND is raised, since table expressions does not support sy-subrc. Don't hate me! I know, this behavior doesn't satisfies all of us!

" old version
READ TABLE customers INTO DATA(customer) WITH KEY id = '00017'.
IF sy-subrc = 0.
  READ TABLE customer-addresses INTO DATA(billing_address) INDEX 1.
  IF sy-subrc = 0.
    billing_address-zip_code = 'NH32211'.
  ENDIF.
ENDIF.

" new version
TRY.
  customers[ id = '00017' ]-addresses[ 1 ]-zip_code = 'NH32211'.
  CATCH cx_sy_itab_line_not_found INTO DATA(itab_line_not_found).
    " handling exceptions
ENDTRY.

For this reason, SAP gives us other features, like using built-in table functions! One of them is the line_exists( ... ), which we can think as the short form of the READ TABLE ... TRANSPORTING NO FIELDS statement. First, we check the existence of the specified row, and if it exists, then we perform the modification.

" new version with line_exists( ... )
IF line_exists( customers[ id = '00017' ]-addresses[ 1 ] ).
  customers[ id = '00017' ]-addresses[ 1 ]-zip_code = 'NH32211'.  
ENDIF.

From 7.40, SP08 on, we are able to define default values for avoiding the mentioned exception above. So, if the specified row is not found, then it returns the default value back.

DATA(default_customer) = VALUE customer( id = '00000' name = 'not found' ... ).

DATA(john_mayer) = VALUE #( customers[ id = '00017' ] DEFAULT default_customer ).


Summary

I hope, I could convince you about that the table expressions are very useful, and efficient features of our ABAP toolset. Of course, there are cases, when we have to use the old, great READ TABLE statement (for example: parallel cursor), but there are many other cases when we only want to read from a simple internal table. The point is that if you find yourself writing deep, complex read statements, then stop for a second and give a try to the table expressions. However, keep in mind, that readability is much more important, than using new and fancy features, so use the table expressions if you find them readable in the given context!

Now, go and try it out! If you don't have any access to any 7.4 based SAP system, then I recommend to watch my colleague's setup guide.

Stay tuned, keep reading! If you want to get notification about the newest posts, follow me or subscribe to our newsletter!

If you liked it, please share it! Thanks!

blog comments powered by Disqus