Le Virtual Sorting permet le traitement trié des tables internes sans modifier l’ordre physique des lignes. Avec la syntaxe SORT ... BY dans les expressions de table et les itérations, vous pouvez parcourir les données dans un ordre spécifique tandis que la table originale reste inchangée.
Qu’est-ce que le Virtual Sorting ?
Le Virtual Sorting est un concept où l’ordre de tri est défini temporairement pour une opération, sans modifier la table elle-même. C’est particulièrement utile quand :
- Plusieurs ordres de tri sont nécessaires en parallèle
- La table originale ne doit pas être modifiée
- La performance est critique sur de grandes tables
| Aspect | SORT physique | Virtual Sorting |
|---|---|---|
| Table originale | Est modifiée | Reste inchangée |
| Ordre | Permanent | Temporaire pour l’opération |
| Plusieurs tris | Successivement | Possible en parallèle |
| Mémoire | In-Place | Index supplémentaire |
Disponibilité
Le Virtual Sorting avec FOR ... IN ... USING KEY et les clés dynamiques est disponible depuis ABAP 7.40. Les possibilités étendues avec les clés secondaires sont entièrement compatibles ABAP Cloud.
Exemple pratique : Analyser les données de ventes
Un scénario typique est l’analyse des données de ventes qui doivent être évaluées dans différents ordres :
CLASS zcl_virtual_sorting DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION. INTERFACES if_oo_adt_classrun.
TYPES: BEGIN OF ty_s_sale, sale_id TYPE i, product TYPE string, region TYPE string, amount TYPE p DECIMALS 2, sale_date TYPE d, END OF ty_s_sale.
" Table avec clés secondaires pour le tri virtuel TYPES ty_t_sales TYPE SORTED TABLE OF ty_s_sale WITH UNIQUE KEY sale_id WITH NON-UNIQUE SORTED KEY by_amount COMPONENTS amount DESCENDING WITH NON-UNIQUE SORTED KEY by_region COMPONENTS region WITH NON-UNIQUE SORTED KEY by_date COMPONENTS sale_date DESCENDING.
ENDCLASS.
CLASS zcl_virtual_sorting IMPLEMENTATION.
METHOD if_oo_adt_classrun~main. DATA(lt_sales) = VALUE ty_t_sales( ( sale_id = 1 product = 'Laptop' region = 'Nord' amount = '1200.00' sale_date = '20260110' ) ( sale_id = 2 product = 'Écran' region = 'Sud' amount = '450.00' sale_date = '20260115' ) ( sale_id = 3 product = 'Clavier' region = 'Nord' amount = '89.00' sale_date = '20260112' ) ( sale_id = 4 product = 'Serveur' region = 'Ouest' amount = '5500.00' sale_date = '20260108' ) ( sale_id = 5 product = 'Souris' region = 'Sud' amount = '35.00' sale_date = '20260120' ) ).
out->write( '=== Ordre original (par sale_id) ===' ). LOOP AT lt_sales INTO DATA(ls_sale). out->write( |{ ls_sale-sale_id }: { ls_sale-product } - { ls_sale-amount }| ). ENDLOOP.
out->write( '' ). out->write( '=== Par chiffre d''affaires (le plus élevé en premier) ===' ). LOOP AT lt_sales INTO ls_sale USING KEY by_amount. out->write( |{ ls_sale-product }: { ls_sale-amount } EUR| ). ENDLOOP.
out->write( '' ). out->write( '=== Par région ===' ). LOOP AT lt_sales INTO ls_sale USING KEY by_region. out->write( |{ ls_sale-region }: { ls_sale-product }| ). ENDLOOP.
out->write( '' ). out->write( '=== Par date (les plus récentes en premier) ===' ). LOOP AT lt_sales INTO ls_sale USING KEY by_date. out->write( |{ ls_sale-sale_date DATE = USER }: { ls_sale-product }| ). ENDLOOP. ENDMETHOD.
ENDCLASS.Clés secondaires pour le Virtual Sorting
La clé du Virtual Sorting réside dans les clés de table secondaires. Elles définissent des ordres de tri alternatifs que le noyau ABAP gère automatiquement.
Types de clés
" Clé primaire (identification)WITH UNIQUE KEY sale_id
" Clé SORTED secondaire (maintenue automatiquement triée)WITH NON-UNIQUE SORTED KEY by_amount COMPONENTS amount DESCENDING
" Clé HASHED secondaire (pour les recherches rapides)WITH UNIQUE HASHED KEY by_product COMPONENTS productComparaison : Physique vs. Virtuel
CLASS zcl_sort_comparison DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION. INTERFACES if_oo_adt_classrun.
TYPES: BEGIN OF ty_s_item, item_id TYPE i, name TYPE string, value TYPE p DECIMALS 2, END OF ty_s_item.
TYPES ty_t_items TYPE SORTED TABLE OF ty_s_item WITH UNIQUE KEY item_id WITH NON-UNIQUE SORTED KEY by_value COMPONENTS value DESCENDING.
ENDCLASS.
CLASS zcl_sort_comparison IMPLEMENTATION.
METHOD if_oo_adt_classrun~main. DATA(lt_items) = VALUE ty_t_items( ( item_id = 1 name = 'A' value = '100.00' ) ( item_id = 2 name = 'B' value = '300.00' ) ( item_id = 3 name = 'C' value = '200.00' ) ).
" Tri PHYSIQUE - modifie la table DATA(lt_sorted_copy) = lt_items. SORT lt_sorted_copy BY value DESCENDING.
out->write( '=== Copie triée physiquement ===' ). LOOP AT lt_sorted_copy INTO DATA(ls_sorted). out->write( |{ ls_sorted-name }: { ls_sorted-value }| ). ENDLOOP.
" Tri VIRTUEL - l'original reste inchangé out->write( '' ). out->write( '=== Trié virtuellement (USING KEY) ===' ). LOOP AT lt_items INTO DATA(ls_virtual) USING KEY by_value. out->write( |{ ls_virtual-name }: { ls_virtual-value }| ). ENDLOOP.
" L'original est inchangé out->write( '' ). out->write( '=== Original (inchangé) ===' ). LOOP AT lt_items INTO DATA(ls_original). out->write( |{ ls_original-name }: { ls_original-value }| ). ENDLOOP. ENDMETHOD.
ENDCLASS.Virtual Sorting avec les expressions FOR
Le Virtual Sorting fonctionne également dans les constructions fonctionnelles comme les boucles FOR et REDUCE :
CLASS zcl_virtual_sort_for DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION. INTERFACES if_oo_adt_classrun.
TYPES: BEGIN OF ty_s_order, order_id TYPE i, customer TYPE string, amount TYPE p DECIMALS 2, priority TYPE i, END OF ty_s_order.
TYPES ty_t_orders TYPE SORTED TABLE OF ty_s_order WITH UNIQUE KEY order_id WITH NON-UNIQUE SORTED KEY by_priority COMPONENTS priority WITH NON-UNIQUE SORTED KEY by_amount COMPONENTS amount DESCENDING.
TYPES: BEGIN OF ty_s_output, rank TYPE i, info TYPE string, END OF ty_s_output. TYPES ty_t_output TYPE STANDARD TABLE OF ty_s_output WITH EMPTY KEY.
ENDCLASS.
CLASS zcl_virtual_sort_for IMPLEMENTATION.
METHOD if_oo_adt_classrun~main. DATA(lt_orders) = VALUE ty_t_orders( ( order_id = 101 customer = 'Müller' amount = '500.00' priority = 2 ) ( order_id = 102 customer = 'Schmidt' amount = '1500.00' priority = 1 ) ( order_id = 103 customer = 'Weber' amount = '300.00' priority = 3 ) ( order_id = 104 customer = 'Fischer' amount = '2000.00' priority = 1 ) ).
" FOR avec USING KEY - détermine l'ordre pour le constructeur DATA(lt_by_priority) = VALUE ty_t_output( FOR ls_order IN lt_orders USING KEY by_priority INDEX INTO lv_idx ( rank = lv_idx info = |{ ls_order-customer } (Prio { ls_order-priority }): { ls_order-amount } EUR| ) ).
out->write( '=== Trié par priorité (VALUE FOR) ===' ). LOOP AT lt_by_priority INTO DATA(ls_output). out->write( |{ ls_output-rank }. { ls_output-info }| ). ENDLOOP.
" Top 2 par montant avec REDUCE DATA(lv_top2_total) = REDUCE p DECIMALS 2( INIT sum = CONV p DECIMALS 2( 0 ) count = 0 FOR ls_ord IN lt_orders USING KEY by_amount WHILE count < 2 NEXT sum = sum + ls_ord-amount count = count + 1 ).
out->write( '' ). out->write( |Somme des 2 premières commandes : { lv_top2_total } EUR| ).
" Filtre combiné avec tri virtuel DATA(lt_high_priority) = VALUE ty_t_output( FOR ls_o IN lt_orders USING KEY by_amount WHERE ( priority <= 2 ) INDEX INTO lv_i ( rank = lv_i info = |{ ls_o-customer }: { ls_o-amount }| ) ).
out->write( '' ). out->write( '=== Haute priorité, par montant ===' ). LOOP AT lt_high_priority INTO DATA(ls_hp). out->write( |{ ls_hp-rank }. { ls_hp-info }| ). ENDLOOP. ENDMETHOD.
ENDCLASS.Considérations de performance
Le Virtual Sorting avec des clés secondaires offre des avantages de performance, mais a aussi des coûts :
Quand utiliser les clés secondaires
| Situation | Recommandation |
|---|---|
| Même tri fréquent | Clé secondaire rentable |
| Tri unique | SORT physique plus efficace |
| Plusieurs tris parallèles | Idéal pour les clés secondaires |
| Très grandes tables (>100 000) | Peser les coûts mémoire |
| INSERT/DELETE fréquents | La maintenance des clés coûte en performance |
Mesure de performance
CLASS zcl_virtual_sort_perf DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION. INTERFACES if_oo_adt_classrun.
TYPES: BEGIN OF ty_s_data, id TYPE i, value TYPE p DECIMALS 2, END OF ty_s_data.
" Avec clé secondaire TYPES ty_t_with_key TYPE SORTED TABLE OF ty_s_data WITH UNIQUE KEY id WITH NON-UNIQUE SORTED KEY by_value COMPONENTS value.
" Sans clé secondaire TYPES ty_t_no_key TYPE SORTED TABLE OF ty_s_data WITH UNIQUE KEY id.
ENDCLASS.
CLASS zcl_virtual_sort_perf IMPLEMENTATION.
METHOD if_oo_adt_classrun~main. " Générer des données de test DATA lt_with_key TYPE ty_t_with_key. DATA lt_no_key TYPE ty_t_no_key.
DO 10000 TIMES. DATA(lv_value) = CONV p DECIMALS 2( sy-index MOD 1000 ). INSERT VALUE #( id = sy-index value = lv_value ) INTO TABLE lt_with_key. INSERT VALUE #( id = sy-index value = lv_value ) INTO TABLE lt_no_key. ENDDO.
" Variante 1 : Virtual Sorting avec clé DATA(lv_start1) = cl_abap_context_info=>get_system_time( ). DATA(lv_sum1) = REDUCE p DECIMALS 2( INIT sum = CONV p DECIMALS 2( 0 ) FOR ls_data IN lt_with_key USING KEY by_value NEXT sum = sum + ls_data-value ). DATA(lv_end1) = cl_abap_context_info=>get_system_time( ).
" Variante 2 : SORT physique + itération DATA(lt_copy) = CORRESPONDING ty_t_no_key( lt_no_key ). DATA(lv_start2) = cl_abap_context_info=>get_system_time( ). SORT lt_copy BY value. DATA(lv_sum2) = REDUCE p DECIMALS 2( INIT sum = CONV p DECIMALS 2( 0 ) FOR ls_data IN lt_copy NEXT sum = sum + ls_data-value ). DATA(lv_end2) = cl_abap_context_info=>get_system_time( ).
out->write( |Virtual Sorting : { lv_end1 - lv_start1 } ms| ). out->write( |SORT physique : { lv_end2 - lv_start2 } ms| ). out->write( |Somme identique : { COND #( WHEN lv_sum1 = lv_sum2 THEN 'Oui' ELSE 'Non' ) }| ). ENDMETHOD.
ENDCLASS.Bonnes pratiques
À FAIRE : Utiliser judicieusement les clés secondaires
" BON : Clé pour un tri fréquemment utiliséTYPES ty_t_products TYPE SORTED TABLE OF ty_s_product WITH UNIQUE KEY product_id WITH NON-UNIQUE SORTED KEY by_price COMPONENTS price DESCENDING.
" Itération dans l'ordre souhaitéLOOP AT lt_products INTO DATA(ls_prod) USING KEY by_price. " Traitement par prix décroissantENDLOOP.À NE PAS FAIRE : Définir trop de clés
" MAUVAIS : Trop de clés secondaires" Chaque clé occupe de la mémoire et coûte lors des INSERT/DELETETYPES ty_t_overkill TYPE SORTED TABLE OF ty_s_data WITH UNIQUE KEY id WITH NON-UNIQUE SORTED KEY k1 COMPONENTS field1 WITH NON-UNIQUE SORTED KEY k2 COMPONENTS field2 WITH NON-UNIQUE SORTED KEY k3 COMPONENTS field3 WITH NON-UNIQUE SORTED KEY k4 COMPONENTS field4 WITH NON-UNIQUE SORTED KEY k5 COMPONENTS field5. " Trop !
" MIEUX : Uniquement les clés vraiment nécessairesTYPES ty_t_balanced TYPE SORTED TABLE OF ty_s_data WITH UNIQUE KEY id WITH NON-UNIQUE SORTED KEY by_priority COMPONENTS priority.Compatibilité ABAP Cloud
| Aspect | Statut |
|---|---|
| BTP ABAP Environment | Entièrement supporté |
| S/4HANA Cloud | Entièrement supporté |
| S/4HANA On-Premise | À partir de 7.40 |
| Statut Released API | Fonctionnalité du langage de base |
Le Virtual Sorting avec des clés secondaires est une fonctionnalité de base d’ABAP et peut être utilisé dans tous les environnements ABAP Cloud sans restrictions.
Résumé
Le Virtual Sorting permet des solutions élégantes pour les tris multiples :
- Les clés secondaires définissent des ordres de tri alternatifs
- USING KEY active le tri virtuel dans LOOP et FOR
- L’original reste inchangé - pas d’effets de bord
- Avantage de performance pour les tris répétés
- Coûts mémoire des clés secondaires à considérer
- Combinable avec REDUCE, VALUE, et autres constructions fonctionnelles
Particulièrement dans les scénarios de reporting, où les données doivent être présentées dans différentes vues, le Virtual Sorting est une solution élégante et performante.