L’expression FILTER crée une copie filtrée d’une table interne. C’est l’alternative moderne et performante à LOOP AT ... WHERE avec APPEND. Prérequis : La table source nécessite une clé triée ou hachée.
Syntaxe
1. Filtrer avec condition WHERE
FILTER <type>( <table_source> [ USING KEY <clé> ] WHERE <condition>)2. Filtrer avec table de filtre (IN)
FILTER <type>( <table_source> [ USING KEY <clé> ] IN <table_filtre> WHERE <champ> = <champ_filtre>)3. Filtrer avec EXCEPT (NOT IN)
FILTER <type>( <table_source> [ EXCEPT [ IN <table_filtre> ] ] WHERE <condition>)Prérequis
Important : FILTER nécessite une clé triée ou hachée sur les champs de filtre :
" SORTED TABLE avec cléDATA: lt_data TYPE SORTED TABLE OF ty_data WITH UNIQUE KEY id.
" STANDARD TABLE avec clé triée secondaireDATA: lt_data TYPE STANDARD TABLE OF ty_data WITH NON-UNIQUE SORTED KEY by_status COMPONENTS status.Exemples
1. Filtrage de base avec WHERE
TYPES: BEGIN OF ty_order, order_id TYPE i, status TYPE string, amount TYPE p DECIMALS 2, END OF ty_order.
" Table triée requiseDATA: lt_orders TYPE SORTED TABLE OF ty_order WITH UNIQUE KEY order_id WITH NON-UNIQUE SORTED KEY by_status COMPONENTS status.
lt_orders = VALUE #( ( order_id = 1 status = 'OPEN' amount = '100.00' ) ( order_id = 2 status = 'COMPLETED' amount = '200.00' ) ( order_id = 3 status = 'OPEN' amount = '150.00' ) ( order_id = 4 status = 'CANCELLED' amount = '50.00' ) ( order_id = 5 status = 'OPEN' amount = '300.00' )).
" Filtrer uniquement les commandes ouvertesDATA(lt_open_orders) = FILTER #( lt_orders USING KEY by_status WHERE status = 'OPEN").
" Résultat : order_id 1, 3, 5LOOP AT lt_open_orders INTO DATA(ls_order). WRITE: / ls_order-order_id, ls_order-amount.ENDLOOP.2. Comparaison : FILTER vs. LOOP AT WHERE
" CLASSIQUE : Avec LOOP et APPENDDATA: lt_result TYPE TABLE OF ty_order.LOOP AT lt_orders INTO DATA(ls_ord) WHERE status = 'OPEN'. APPEND ls_ord TO lt_result.ENDLOOP.
" MODERNE : Avec FILTER (plus performant sur grandes tables)DATA(lt_result2) = FILTER #( lt_orders USING KEY by_status WHERE status = 'OPEN").3. Filtrer avec table de filtre (IN)
TYPES: BEGIN OF ty_product, product_id TYPE i, category TYPE string, name TYPE string, END OF ty_product.
DATA: lt_products TYPE SORTED TABLE OF ty_product WITH UNIQUE KEY product_id WITH NON-UNIQUE SORTED KEY by_cat COMPONENTS category.
lt_products = VALUE #( ( product_id = 1 category = 'A' name = 'Produit 1' ) ( product_id = 2 category = 'B' name = 'Produit 2' ) ( product_id = 3 category = 'A' name = 'Produit 3' ) ( product_id = 4 category = 'C' name = 'Produit 4' ) ( product_id = 5 category = 'B' name = 'Produit 5' )).
" Table de filtre avec catégories souhaitéesTYPES: BEGIN OF ty_filter, category TYPE string, END OF ty_filter.
DATA: lt_filter TYPE SORTED TABLE OF ty_filter WITH UNIQUE KEY category.
lt_filter = VALUE #( ( category = 'A' ) ( category = 'B' )).
" Filtrer les produits dont la catégorie est dans lt_filterDATA(lt_filtered) = FILTER #( lt_products USING KEY by_cat IN lt_filter WHERE category = category).
" Résultat : Produits avec catégorie A et B (product_id 1, 2, 3, 5)4. EXCEPT – Exclure au lieu d’inclure
" Produits SAUF catégorie A et BDATA(lt_except) = FILTER #( lt_products USING KEY by_cat EXCEPT IN lt_filter WHERE category = category).
" Résultat : Uniquement produit 4 (Catégorie C)5. EXCEPT avec WHERE (sans table de filtre)
TYPES: BEGIN OF ty_employee, emp_id TYPE i, department TYPE string, active TYPE abap_bool, END OF ty_employee.
DATA: lt_employees TYPE SORTED TABLE OF ty_employee WITH UNIQUE KEY emp_id WITH NON-UNIQUE SORTED KEY by_active COMPONENTS active.
lt_employees = VALUE #( ( emp_id = 1 department = 'IT' active = abap_true ) ( emp_id = 2 department = 'RH' active = abap_false ) ( emp_id = 3 department = 'IT' active = abap_true ) ( emp_id = 4 department = 'Ventes' active = abap_false )).
" Tous les employés NON actifsDATA(lt_inactive) = FILTER #( lt_employees USING KEY by_active EXCEPT WHERE active = abap_true).
" Résultat : emp_id 2, 46. Conditions multiples
TYPES: BEGIN OF ty_item, id TYPE i, type TYPE string, priority TYPE i, END OF ty_item.
DATA: lt_items TYPE SORTED TABLE OF ty_item WITH UNIQUE KEY id WITH NON-UNIQUE SORTED KEY by_type_prio COMPONENTS type priority.
lt_items = VALUE #( ( id = 1 type = 'A' priority = 1 ) ( id = 2 type = 'A' priority = 2 ) ( id = 3 type = 'B' priority = 1 ) ( id = 4 type = 'A' priority = 1 ) ( id = 5 type = 'C' priority = 3 )).
" Filtrer par type ET prioritéDATA(lt_high_prio_a) = FILTER #( lt_items USING KEY by_type_prio WHERE type = 'A' AND priority = 1).
" Résultat : id 1, 47. FILTER avec table standard et clé secondaire
" Table standard avec clé secondaireDATA: lt_data TYPE STANDARD TABLE OF ty_order WITH NON-UNIQUE SORTED KEY k_status COMPONENTS status.
lt_data = VALUE #( ( order_id = 1 status = 'NEW' amount = 100 ) ( order_id = 2 status = 'DONE' amount = 200 ) ( order_id = 3 status = 'NEW' amount = 150 )).
" FILTER utilise la clé secondaireDATA(lt_new) = FILTER #( lt_data USING KEY k_status WHERE status = 'NEW").8. FILTER dans des appels de méthode
METHODS: process_orders IMPORTING it_orders TYPE ty_orders.
" Passer directement des données filtréesprocess_orders( it_orders = FILTER #( lt_all_orders USING KEY by_status WHERE status = 'PENDING" )).9. FILTER avec table de ranges
TYPES: BEGIN OF ty_sales, sales_id TYPE i, region TYPE string, revenue TYPE p DECIMALS 2, END OF ty_sales.
DATA: lt_sales TYPE SORTED TABLE OF ty_sales WITH UNIQUE KEY sales_id WITH NON-UNIQUE SORTED KEY by_region COMPONENTS region.
lt_sales = VALUE #( ( sales_id = 1 region = 'NORD' revenue = 1000 ) ( sales_id = 2 region = 'SUD' revenue = 2000 ) ( sales_id = 3 region = 'EST' revenue = 1500 ) ( sales_id = 4 region = 'NORD' revenue = 1800 )).
" Table de filtre avec régionsTYPES: BEGIN OF ty_region_filter, region TYPE string, END OF ty_region_filter.
DATA: lt_regions TYPE SORTED TABLE OF ty_region_filter WITH UNIQUE KEY region.
lt_regions = VALUE #( ( region = 'NORD' ) ( region = 'SUD' )).
DATA(lt_filtered_sales) = FILTER #( lt_sales USING KEY by_region IN lt_regions WHERE region = region).10. Combinaison avec d’autres expressions
" Combiner avec VALUE et FORDATA(lt_processed) = VALUE ty_result_tab( FOR ls_item IN FILTER #( lt_items USING KEY by_type_prio WHERE type = 'A" ) ( id = ls_item-id description = |Article { ls_item-id } - Prio { ls_item-priority }| )).
" Avec REDUCE pour agrégationDATA(lv_total) = REDUCE p DECIMALS 2( INIT sum = CONV p DECIMALS 2( 0 ) FOR ls_order IN FILTER #( lt_orders USING KEY by_status WHERE status = 'COMPLETED" ) NEXT sum = sum + ls_order-amount).11. Comparaison de performances
" === INEFFICACE: LOOP sans index ===DATA: lt_result TYPE TABLE OF ty_order.LOOP AT lt_orders INTO ls_order WHERE status = 'OPEN'. APPEND ls_order TO lt_result.ENDLOOP." → Parcours linéaire O(n)
" === EFFICACE: FILTER avec clé ===DATA(lt_result2) = FILTER #( lt_orders USING KEY by_status WHERE status = 'OPEN")." → Utilise l'index pour accès rapide O(log n) à O(1)Quand utiliser FILTER ?
| Situation | Recommandation |
|---|---|
| Table triée/hachée disponible | FILTER #() |
| Filtrer sur champs de clé | FILTER #() |
| Table standard sans clé | LOOP AT … WHERE |
| Conditions complexes (pas dans la clé) | LOOP AT … WHERE |
| Grandes quantités de données avec index | FILTER #() |
| Filtrer avec table IN | FILTER … IN |
FILTER vs. Alternatives
" 1. FILTER #() - Nécessite clé triée/hachéeDATA(lt_a) = FILTER #( lt_data USING KEY k WHERE status = 'X' ).
" 2. LOOP AT ... WHERE - Plus flexible, mais potentiellement plus lentLOOP AT lt_data INTO ls_data WHERE status = 'X'. APPEND ls_data TO lt_b.ENDLOOP.
" 3. FOR ... WHERE - Flexible, utilisable inlineDATA(lt_c) = VALUE ty_tab( FOR ls IN lt_data WHERE ( status = 'X' ) ( ls )).
" 4. REDUCE avec COND - Pour logique de filtre complexeDATA(lt_d) = REDUCE ty_tab( INIT result = VALUE ty_tab( ) FOR ls IN lt_data NEXT result = COND #( WHEN ls-status = 'X' THEN VALUE #( BASE result ( ls ) ) ELSE result )).Remarques importantes / Bonnes pratiques
FILTERnécessite une clé triée ou hachée sur les champs de filtre.- Sans clé appropriée → Erreur de syntaxe.
USING KEYspécifie quelle clé utiliser.FILTERest plus performant queLOOP AT WHEREsur grandes tables avec index.INpermet de filtrer contre une table de filtre (similaire à SQL IN).EXCEPTinverse la logique de filtre (exclure au lieu d’inclure).- Combinez avec
VALUE,FORetREDUCE. - Pour les tables standard sans clé, utilisez
LOOP AT ... WHERE. - La table de filtre avec
INdoit également être triée ou hachée. FILTERcrée une copie – la table originale reste inchangée.