Mastering Dynamic Internal Table Sorting in SAP ABAP

Sorting internal tables dynamically is a powerful feature in SAP ABAP that allows developers to sort tables based on runtime conditions.

Emre Göçmen

Mastering Dynamic Internal Table Sorting in SAP ABAP

Sorting internal tables dynamically is a powerful feature in SAP ABAP that allows developers to sort tables based on runtime conditions. This is especially useful when the sorting criteria are not known at compile time and need to be determined during program execution. In this blog post, we'll explore the intricacies of dynamic internal table sorting, complete with examples and best practices.

Introduction to Dynamic Sorting

In many scenarios, you might need to sort an internal table based on user inputs or other runtime conditions. Dynamic sorting in ABAP provides the flexibility to achieve this by allowing the sort fields and order to be specified programmatically.

Basic Concepts

Before diving into dynamic sorting, let's briefly review the SORT statement in ABAP. The SORT statement is used to sort an internal table based on one or more fields. Here's a simple example:

DATA: lt_table TYPE TABLE OF spfli,
      ls_table TYPE spfli.

* Filling the table with sample data
SELECT * FROM spfli INTO TABLE lt_table.

* Sorting the table by cityfrom in ascending order
SORT lt_table BY cityfrom.

In the above example, the sorting field cityfrom is specified at compile time. However, in dynamic sorting, we determine the sorting fields at runtime.

Dynamic Sorting Using Field Symbols

To dynamically sort an internal table, we use field symbols and dynamic expressions. Here’s a step-by-step guide:

Step 1: Define and Populate the Internal Table

First, define and populate the internal table that you want to sort dynamically.

DATA: lt_table TYPE TABLE OF spfli,
      ls_table TYPE spfli.

* Filling the table with sample data
SELECT * FROM spfli INTO TABLE lt_table.

Step 2: Determine the Sorting Criteria

Determine the sorting criteria based on runtime conditions. This could be user inputs or any other logic in your program.

DATA: lv_sort_field TYPE string.

* Example: setting sort field based on a condition
lv_sort_field = 'CITYTO'. " This could be dynamic based on user input

Step 3: Sort the Table Dynamically

Use the SORT statement with dynamic sorting. The VALUE operator and dynamic expressions are utilized here.

TRY.
    SORT lt_table BY VALUE #( ( name = lv_sort_field ) ).
  CATCH cx_sy_dyn_table_ill_comp_val.
    MESSAGE 'Error in sorting criteria' TYPE 'E'.
ENDTRY.

In this example, the lv_sort_field determines the field by which the table is sorted.

Advanced Dynamic Sorting

For more complex sorting scenarios, such as sorting by multiple fields or in different orders, you can extend the dynamic sorting logic.

DATA: lt_sort_order TYPE abap_sortorder_tab,
      lv_sort_field2 TYPE string.

lv_sort_field = 'CITYFROM'.
lv_sort_field2 = 'CITYTO'.

APPEND VALUE #( name = lv_sort_field ) TO lt_sort_order.
APPEND VALUE #( name = lv_sort_field2 descending = 'X' ) TO lt_sort_order.

TRY.
    SORT lt_table BY lt_sort_order.
  CATCH cx_sy_dyn_table_ill_comp_val.
    MESSAGE 'Error in sorting criteria' TYPE 'E'.
ENDTRY.

In this example, the internal table lt_table is sorted first by CITYFROM in ascending order and then by CITYTO in descending order.

Handling Errors

When performing dynamic sorting, it’s important to handle potential errors. The exceptions CX_SY_DYN_TABLE_ILL_COMP_VAL can be used to catch issues related to invalid sorting criteria.

TRY.
    SORT lt_table BY VALUE #( ( name = lv_sort_field ) ).
  CATCH cx_sy_dyn_table_ill_comp_val.
    MESSAGE 'Error in sorting criteria' TYPE 'E'.
ENDTRY.

Dynamic Sorting with Field Symbols and Dynamic Tables

To sort dynamic internal tables, we use field symbols to dynamically reference and manipulate the tables. Here’s how you can do it:

FIELD-SYMBOLS: <gfs_dyn_table>               TYPE STANDARD TABLE,
               <gfs_dyn_planned>             TYPE STANDARD TABLE,
               <gfs_dyn_unplanned>           TYPE STANDARD TABLE,
               <gfs_dyn_withdate_planned>    TYPE STANDARD TABLE,
               <gfs_dyn_withoutdate_planned> TYPE STANDARD TABLE,
               <gfs_dyn_sorted>              TYPE STANDARD TABLE,
               <ls_table>                    TYPE any.

DATA : gt_planned             TYPE REF TO data,
       gt_unplanned           TYPE REF TO data,
       gt_withdate_planned    TYPE REF TO data,
       gt_withoutdate_planned TYPE REF TO data,
       gt_sorted              TYPE REF TO data.

* Create dynamic internal tables
CREATE DATA gt_planned LIKE <gfs_dyn_table>.
CREATE DATA gt_unplanned LIKE <gfs_dyn_table>.
CREATE DATA gt_withdate_planned LIKE <gfs_dyn_table>.
CREATE DATA gt_withoutdate_planned LIKE <gfs_dyn_table>.
CREATE DATA gt_sorted LIKE <gfs_dyn_table>.

* Assign the dynamic tables to field symbols
ASSIGN gt_planned->* TO <gfs_dyn_planned>.
ASSIGN gt_unplanned->* TO <gfs_dyn_unplanned>.
ASSIGN gt_withdate_planned->* TO <gfs_dyn_withdate_planned>.
ASSIGN gt_withoutdate_planned->* TO <gfs_dyn_withoutdate_planned>.
ASSIGN gt_sorted->* TO <gfs_dyn_sorted>.

* Read and separate data based on the planning status
LOOP AT <gfs_dyn_table> ASSIGNING <ls_table>.
  ASSIGN COMPONENT 'PLANLANDI' OF STRUCTURE <ls_table> TO FIELD-SYMBOL(<lv_plan>).
  IF <lv_plan> IS NOT INITIAL.
    APPEND <ls_table> TO <gfs_dyn_planned>.
  ELSE.
    APPEND <ls_table> TO <gfs_dyn_unplanned>.
  ENDIF.
ENDLOOP.

* Separate planned data into with and without material ready date
LOOP AT <gfs_dyn_planned> ASSIGNING <ls_table>.
  ASSIGN COMPONENT 'DELIVERY_DATE' OF STRUCTURE <ls_table> TO FIELD-SYMBOL(<lv_date>).
  IF <lv_date> IS NOT INITIAL AND <lv_date> NE '00000000'.
    APPEND <ls_table> TO <gfs_dyn_withdate_planned>.
  ELSE.
    APPEND <ls_table> TO <gfs_dyn_withoutdate_planned>.
  ENDIF.
ENDLOOP.

* Sort records with material ready date from oldest to newest within same production 
*start date
SORT <gfs_dyn_withdate_planned> BY VALUE #( ( name = 'URETIM_BASLAMA_TARIH' )
                                         ( name = 'DELIVERY_DATE' ) ).

* Sort records without material ready date by priority in descending order within 
*same production start date
SORT <gfs_dyn_withoutdate_planned> BY VALUE #( ( name = 'URETIM_BASLAMA_TARIH' )
                                       ( name = 'ONCELIK' descending = 'X' ) ).

* Combine sorted tables
APPEND LINES OF <gfs_dyn_withdate_planned> TO <gfs_dyn_sorted>.
APPEND LINES OF <gfs_dyn_withoutdate_planned> TO <gfs_dyn_sorted>.
APPEND LINES OF <gfs_dyn_unplanned> TO <gfs_dyn_sorted>.

* Refresh and copy the results back to the original table
REFRESH <gfs_dyn_table>.
APPEND LINES OF <gfs_dyn_sorted> TO <gfs_dyn_table>.

This code demonstrates how to sort dynamic internal tables based on different conditions and combine them while maintaining the primary sort order.

Practical Example

Let’s put it all together in a practical example where the sorting criteria are determined based on user input:

DATA: lt_table TYPE TABLE OF spfli,
      ls_table TYPE spfli,
      lv_sort_field TYPE string,
      lt_sort_order TYPE abap_sortorder_tab.

* Filling the table with sample data
SELECT * FROM spfli INTO TABLE lt_table.

* User input to determine sorting field
PARAMETERS: p_sort TYPE string.

lv_sort_field = p_sort.

APPEND VALUE #( name = lv_sort_field ) TO lt_sort_order.

TRY.
    SORT lt_table BY lt_sort_order.
  CATCH cx_sy_dyn_table_ill_comp_val.
    MESSAGE 'Invalid sort field' TYPE 'E'.
ENDTRY.

* Display sorted table
LOOP AT lt_table INTO ls_table.
  WRITE: / ls_table-carrid, ls_table-connid, ls_table-cityfrom, ls_table-cityto.
ENDLOOP.

In this example, the user specifies the sorting field via the parameter p_sort, and the internal table is sorted accordingly.

Conclusion

Dynamic internal table sorting in ABAP provides a robust way to handle sorting requirements that are determined at runtime. By using field symbols, dynamic expressions, and handling potential errors, you can create flexible and efficient sorting logic in your ABAP programs. This guide should equip you with the knowledge to implement dynamic sorting in various scenarios, enhancing the functionality and user experience of your applications.