Skip to Content

SAP NetWeaver AS for ABAP 7.52 is available now.

It is mainly a “major step on the way to efficient development of SAP HANA optimized SAP Fiori apps is the use of the new RESTful ABAP programming model which includes technologies such as CDS, Business Object Processing Framework (BOPF), SAP Gateway and SAPUI5.”

But there are some news in the ABAP language too.

One of those is virtual sorting of internal tables.

Virtual Sorting of Internal Tables

There is a new method VIRTUAL_SORT of class CL_ABAP_ITAB_UTILITIES. With that method, you can virtually sort a set of internal tables. The internal tables of such a set must contain the same number of lines. The method VIRTUAL_SORT treats the set of internal tables as one combined table containing all the columns of the involved internal tables. It sorts that virtual combined table ascending or descending by the columns whose names are passed to the method and returns an array of line numbers of the virtually sorted combined table. This allows you to sort internal tables without changing the order of lines of the internal tables itself, e.g. to generate various sorted output data without affecting the original data.

Step by Step

Let me show it to you in a step by step example.

First, we create some example data in three internal tables.

TYPES:
  BEGIN OF flight,
    carrid   TYPE s_carr_id,
    connid   TYPE s_conn_id,
    cityfrom TYPE s_city,
    cityto   TYPE s_city,
  END OF flight,
  flights TYPE STANDARD TABLE OF flight
          WITH EMPTY KEY,
  BEGIN OF city,
    city      TYPE  s_city,
    latitude  TYPE  s_lati,
    longitude TYPE  s_long,
  END OF city,
  cities TYPE STANDARD TABLE OF city
              WITH EMPTY KEY.
DATA:
  flight_tab    TYPE flights,
  from_city_tab TYPE cities,
  to_city_tab   TYPE cities.


SELECT carrid, connid, cityfrom, cityto
       FROM spfli
       INTO CORRESPONDING FIELDS OF TABLE @flight_tab.

SELECT city, latitude, longitude
       FROM sgeocity
       INTO TABLE @DATA(cities).

TRY.
    from_city_tab = VALUE #( FOR <fs> IN flight_tab
                             ( cities[ city = <fs>-cityfrom ] ) ).
    to_city_tab   = VALUE #( FOR <fs> IN flight_tab
                             ( cities[ city = <fs>-cityto ] ) ).
  CATCH cx_sy_itab_line_not_found.
    MESSAGE 'Flight model data not consistent,' &&
            ' use program SAPBC_DATA_GENERATOR' &&
            ' to create the data.' TYPE 'X'.
ENDTRY.

There is an internal table flight_tab containing flight data. Two additional tables from_city_tab and to_city_tab are constructed with lines containing the longitudes and latitudes of the departure and arrival cities from the respective lines of flight_tab.

Let’s sort the flight data virtually by the longitudes and latitudes of the departure and arrival cities, ascending and descending:

DATA(sort_asc) = cl_abap_itab_utilities=>virtual_sort(
                   im_virtual_source =
                     VALUE #(
                       ( source     = REF #( from_city_tab )
                         components =
                           VALUE #( ( name = 'latitude' )
                                    ( name = 'longitude' ) ) )
                       ( source     = REF #( to_city_tab )
                         components =
                           VALUE #( ( name = 'latitude' )
                                    ( name = 'longitude' ) ) )
                       ( source     = REF #( flight_tab )
                         components =
                           VALUE #( ( name = 'carrid' )
                                    ( name = 'connid' ) ) ) ) ).

cl_demo_output=>display( sort_asc ).

DATA(sort_desc) = cl_abap_itab_utilities=>virtual_sort(
                   im_virtual_source =
                     VALUE #(
                       ( source     = REF #( from_city_tab )
                         components =
                           VALUE #( ( name = 'latitude'
                                      descending = abap_true )
                                    ( name = 'longitude'
                                      descending = abap_true ) ) )
                       ( source     = REF #( to_city_tab )
                         components =
                           VALUE #( ( name = 'latitude'
                                      descending = abap_true )
                                    ( name = 'longitude'
                                      descending = abap_true ) ) )
                       ( source     = REF #( flight_tab )
                         components =
                           VALUE #( ( name = 'carrid' )
                                    ( name = 'connid' ) ) ) ) ).
cl_demo_output=>display( sort_desc ).

The virtual sorting involves all three internal tables.We simply pass references to the internal tables, the names of the columns used for sorting, and the sort order to method cl_abap_itab_utilities=>virtual_sort. The results are arrays of the line numbers resulting from the ascending and descending sortings.

Normally, you do not want to look at these values, but use them for constructing an output:

DATA sorted_tab TYPE flights.

LOOP AT sort_asc ASSIGNING FIELD-SYMBOL(<idx>).
  APPEND flight_tab[ <idx> ] TO sorted_tab.
ENDLOOP.

cl_demo_output=>display( sorted_tab ).

CLEAR sorted_tab.
LOOP AT sort_desc ASSIGNING <idx>.
  APPEND flight_tab[ <idx> ] TO sorted_tab.
ENDLOOP.

cl_demo_output=>display( sorted_tab ).

You see the flight data sorted ascending and descending by the longitudes and latitudes of the departure and arrival cities.

If you don’t need the data later, declaring and filling an explicit helper table sorted_tab is not necessary in modern times. Therefore, let’s put it together.

Putting it Together

The following coding shows the same virtual sorting as above in one single statement.

cl_demo_output=>new(

  )->next_section(
  `Ascending Sort by Latitude, Longitude of CITYFROM, CITYTO`

  )->write( VALUE flights(
              FOR <idx>
              IN cl_abap_itab_utilities=>virtual_sort(
                   im_virtual_source =
                     VALUE #(
                       ( source     = REF #( from_city_tab )
                         components =
                           VALUE #( ( name = 'latitude' )
                                    ( name = 'longitude' ) ) )
                       ( source     = REF #( to_city_tab )
                         components =
                           VALUE #( ( name = 'latitude' )
                                    ( name = 'longitude' ) ) )
                       ( source     = REF #( flight_tab )
                         components =
                           VALUE #( ( name = 'carrid' )
                                    ( name = 'connid' ) ) ) ) )
              ( flight_tab[ <idx> ] ) )

  )->next_section(
  `Descending Sort by Latitude, Longitude of CITYFROM, CITYTO`

  )->write( VALUE flights(
              FOR <idx>
              IN cl_abap_itab_utilities=>virtual_sort(
                   im_virtual_source =
                     VALUE #(
                       ( source     = REF #( from_city_tab )
                         components =
                           VALUE #( ( name = 'latitude'
                                      descending = abap_true )
                                    ( name = 'longitude'
                                      descending = abap_true ) ) )
                       ( source     = REF #( to_city_tab )
                         components =
                           VALUE #( ( name = 'latitude'
                                      descending = abap_true )
                                    ( name = 'longitude'
                                      descending = abap_true ) ) )
                       ( source     = REF #( flight_tab )
                         components =
                           VALUE #( ( name = 'carrid' )
                                    ( name = 'connid' ) ) ) ) )
              ( flight_tab[ <idx> ] ) )

  )->display( ).

Now the virtual sorting with the method VIRTUAL_SORT of class CL_ABAP_ITAB_UTILITIES takes place at the operand position of a FOR expression for a table iteration. The temporary result of the sorting is used to construct a sorted internal table from the lines of flight_tab. This table is also only temporary and is an input parameter of the method WRITE of class CL_DEMO_OUTPUT.

The sorting in ascending order and in descending order does not change the order of the lines in the internal tables that are involved. These remain in their original unsorted state.

Bottom Line

Virtual sorting makes it possible to generate various sorted output data without affecting the original data.

 

 

To report this post you need to login first.

18 Comments

You must be Logged on to comment or reply to a post.

  1. Raphael Pacheco

    Hmmm, this looks good, waiting for download this version and test it (also to know more about 7.52) 🙂

    About performance, what change for us using this new statment?

    BR,

    Raphael Pacheco.

    (0) 
  2. Michelle Crapo

    Hi Horst,

    I love this!!!   Now I have to bookmark it for the future.   It seems like I’ve been doing that a lot lately.

    Teched information and year – it tends to blur if you’ve been to a lot of them.  I just remember some of the good information shared.   And if I’m trying something new – I tend to look up to see if it was covered in one of the techeds – or – I bookmarked it.

    So I can’t use it now, but will in the future.

    Thank you!

    Michelle

    (0) 
  3. Paul Hardy

    Is anyone at SAP going to say explicitly that ABAP 7.50 is the final release for ECC 6.0?

    My guess is that if SAP keep making ECC 6.0 better, that reduces the incentive to go to S/4 HANA….

     

    (0) 
  4. Daniel Gent

    Interesting, I hope I’ll remember this post when the time comes and I could need this. But if I understand it correctly, i could also use this method to use a “virtually” sorted version of a single internal table somewhere within another expression.

    (0) 
  5. Paul Hardy

    I am finding it very difficult to see a practical application for this in the real world. I have been trying to keep an open mind and asking assorted colleagues what this could be used for, but no-one can work it out.

    It is useful to know this is available and one day I might find a nail which needs this particular hammer but usually I tend not to have several identical sized tables with different columns, with all the tables relating to the same record.

    In regard to sorted helper tables, is that not what secndary keys were designed to solve?

    Can anyone think of a use case for this?

    Horst – do you know if this is being used internally in any SAP standard code, and if so what for?

    On a final note – some of the new constructs can make code look more readable, but this is not one of them. And, cranking the pedantic meter up to overdrive, why name a variable IDX when you could call it INDEX?

    (0) 
    1. Horst Keller Post author

       

      It was demanded and is used internally by ALV.

      And in fact, from hotline service I also know about other programs that created their own auxiliary index tables with different sort orders for one internal table.

      (0) 
      1. Paul Hardy

        It would be lovely to know what it was being used for under the hood for the ALV. And my users “demand” things as well but sometimes without a clear use for what they are demanding.

        In regard to creating several auxillary internal tables sorted different ways I used to do that as well, but now I use a secondary index so I only have one internal table that can be accessed in dfferent ways.

        Unless there is an advantage to using the virtual approach over using a secondary index on an internal table?

         

        (0) 
        1. Horst Keller Post author

           

          You’re inside a procedure with a generically typed tabular parameter and want to sort that in different ways. How do you add secondary indices to such a parameter?

          (0) 
          1. Paul Hardy

            OK that is a valid use case. I knew I could tease one out of you if I tried hard enough!

            We have a generic table coming in to the method as an importing parameter so naturally it cannot be changed. Now we want to sort that table by column four and sometimes column five.

            Previously we would have had to create two duplicate tables and sort each one differently. Or one duplicate table with two secondary keys.

            Now with virtual sorting you can get the index numbers telling you what the incoming table would look like if it was sorted different ways.

            But you still have to create the duplicate tables?

             

            (0) 
            1. Horst Keller Post author

              “But you still have to create the duplicate tables?”

              Depends if you need them. For paging purposes (ALV!) you might need only sections.

              (0) 

Leave a Reply