L’instruction READ TABLE sert à lire une seule ligne spécifique d’une table interne. Contrairement à LOOP AT, qui parcourt toutes ou plusieurs lignes, READ TABLE est optimisé pour l’accès ciblé à exactement une ligne – soit par la clé de table, un index ou une condition de recherche libre.
Syntaxe
Il existe différentes variantes pour identifier la ligne souhaitée :
1. Recherche via champs de clé (WITH KEY)
READ TABLE <table_interne> INTO <zone_travail> | ASSIGNING <field_symbol> | REFERENCE INTO <data_reference> WITH KEY <composante1> = <valeur1> [<composante2> = <valeur2> ...] [BINARY SEARCH].2. Recherche via clé de table (WITH TABLE KEY)
READ TABLE <table_interne> INTO <zone_travail> | ASSIGNING <field_symbol> | REFERENCE INTO <data_reference> WITH TABLE KEY <cle_composante1> = <valeur1> [<cle_composante2> = <valeur2> ...].3. Accès via index (INDEX)
READ TABLE <table_interne> INTO <zone_travail> | ASSIGNING <field_symbol> | REFERENCE INTO <data_reference> INDEX <index>.4. Recherche avec condition libre (WITH KEY ... COMPONENTS)
READ TABLE <table_interne> INTO <zone_travail> | ASSIGNING <field_symbol> | REFERENCE INTO <data_reference> WITH KEY <composante_table> COMPONENTS <composante1> = <valeur1> [...].5. Vérification d’existence uniquement sans transport de données
READ TABLE <table_interne> TRANSPORTING NO FIELDS WITH KEY <composante> = <valeur>.Composantes
<table_interne>: La table dans laquelle effectuer la recherche.INTO <zone_travail>: La ligne trouvée est copiée dans la zone de travail.ASSIGNING <field_symbol>: Le symbole de champ pointe directement sur la ligne trouvée.REFERENCE INTO <data_reference>: Une référence de données sur la ligne trouvée.WITH KEY: Recherche via composantes quelconques (pas forcément la clé de table).WITH TABLE KEY: Recherche via la clé primaire définie de la table (optimisé).INDEX <index>: Accès direct à la ligne à la position indiquée.BINARY SEARCH: Recherche binaire (uniquement pour les tables standard triées – la table doit être triée !).TRANSPORTING NO FIELDS: Aucune donnée n’est transportée, seulssy-subrcetsy-tabixsont définis.
Champs système
Après un READ TABLE, les champs système suivants sont définis :
-
sy-subrc:0: Ligne trouvée.4: Aucune ligne correspondante trouvée.8: (AvecBINARY SEARCH) Ligne non trouvée, maissy-tabixpointe sur la position d’insertion.
-
sy-tabix: Contient l’index de la ligne trouvée (pour les tables indexées). Pour les tables de hachage,sy-tabixn’est pas défini.
Comportement de recherche selon le type de table
Le comportement de recherche et la performance dépendent du type de table :
| Type de table | WITH KEY | WITH TABLE KEY | INDEX | Performance |
|---|---|---|---|---|
| STANDARD TABLE | Recherche linéaire O(n) | Recherche linéaire O(n) | O(1) | Lent pour grandes tables |
| SORTED TABLE | Recherche binaire O(log n) | Recherche binaire O(log n) | O(1) | Rapide |
| HASHED TABLE | Hash-Lookup O(1) | Hash-Lookup O(1) | Impossible | Très rapide |
Exemples
1. READ TABLE avec INTO (Copie)
TYPES: BEGIN OF ty_customer, id TYPE i, name TYPE string, city TYPE string, END OF ty_customer.
DATA: lt_customers TYPE STANDARD TABLE OF ty_customer WITH EMPTY KEY, ls_customer TYPE ty_customer.
" Remplir la tablelt_customers = VALUE #( ( id = 1 name = 'Müller GmbH' city = 'Berlin' ) ( id = 2 name = 'Schmidt AG' city = 'München' ) ( id = 3 name = 'Weber KG' city = 'Hamburg' )).
" Rechercher le client avec ID 2READ TABLE lt_customers INTO ls_customer WITH KEY id = 2.
IF sy-subrc = 0. WRITE: / 'Trouvé:', ls_customer-name, 'à', ls_customer-city. WRITE: / 'Index:', sy-tabix.ELSE. WRITE: / 'Client non trouvé.'.ENDIF.2. READ TABLE avec ASSIGNING (Accès direct)
FIELD-SYMBOLS: <fs_customer> TYPE ty_customer.
" Rechercher le client et modifier directementREAD TABLE lt_customers ASSIGNING <fs_customer> WITH KEY id = 1.
IF sy-subrc = 0. " La modification agit directement dans la table <fs_customer>-city = 'Frankfurt'. WRITE: / 'Ville modifiée en:', <fs_customer>-city.ELSE. WRITE: / 'Client non trouvé.'.ENDIF.3. READ TABLE avec INDEX
" Lire la première ligneREAD TABLE lt_customers INTO ls_customer INDEX 1.
IF sy-subrc = 0. WRITE: / 'Première ligne:', ls_customer-name.ENDIF.
" Lire la dernière ligneREAD TABLE lt_customers INTO ls_customer INDEX lines( lt_customers ).
IF sy-subrc = 0. WRITE: / 'Dernière ligne:', ls_customer-name.ENDIF.4. READ TABLE avec BINARY SEARCH
" IMPORTANT: La table doit être triée selon le champ de recherche !" Voir: /sort-statement/SORT lt_customers BY id.
READ TABLE lt_customers INTO ls_customer WITH KEY id = 2 BINARY SEARCH.
IF sy-subrc = 0. WRITE: / 'Trouvé (binaire):', ls_customer-name.ENDIF.Attention: BINARY SEARCH sur une table non triée fournit des résultats incorrects sans message d’erreur !
5. READ TABLE avec TRANSPORTING NO FIELDS
" Vérifier uniquement si un client existeREAD TABLE lt_customers TRANSPORTING NO FIELDS WITH KEY city = 'Berlin'.
IF sy-subrc = 0. WRITE: / 'Au moins un client à Berlin (Index:', sy-tabix, ').'.ELSE. WRITE: / 'Aucun client à Berlin.'.ENDIF.6. READ TABLE avec plusieurs champs de clé
TYPES: BEGIN OF ty_order, customer_id TYPE i, order_id TYPE i, amount TYPE p DECIMALS 2, END OF ty_order.
DATA: lt_orders TYPE STANDARD TABLE OF ty_order WITH EMPTY KEY, ls_order TYPE ty_order.
lt_orders = VALUE #( ( customer_id = 1 order_id = 100 amount = '1500.00' ) ( customer_id = 1 order_id = 101 amount = '2300.50' ) ( customer_id = 2 order_id = 100 amount = '800.00' )).
" Rechercher la commande pour le client 1, commande 101READ TABLE lt_orders INTO ls_order WITH KEY customer_id = 1 order_id = 101.
IF sy-subrc = 0. WRITE: / 'Montant:', ls_order-amount.ENDIF.7. READ TABLE avec REFERENCE INTO
DATA: lr_customer TYPE REF TO ty_customer.
READ TABLE lt_customers REFERENCE INTO lr_customer WITH KEY id = 3.
IF sy-subrc = 0. " Accès via déréférencement WRITE: / 'Nom:', lr_customer->name. lr_customer->city = 'Köln'. " Modifie directement la tableENDIF.Alternative moderne : Expressions de table (à partir d’ABAP 7.40)
À partir d’ABAP 7.40, les expressions de table peuvent être utilisées comme alternative compacte :
Accès en ligne avec expression de table
" Accès direct (lève une exception si non trouvé)TRY. DATA(ls_found) = lt_customers[ id = 2 ]. WRITE: / 'Trouvé:', ls_found-name. CATCH cx_sy_itab_line_not_found. WRITE: / 'Non trouvé.'.ENDTRY.
" Accès par indexDATA(ls_first) = lt_customers[ 1 ].
" Avec OPTIONAL (retourne une ligne initiale si non trouvé)DATA(ls_safe) = VALUE #( lt_customers[ id = 99 ] OPTIONAL ).
" Avec DEFAULT (retourne une valeur par défaut si non trouvé)DATA(ls_default) = VALUE #( lt_customers[ id = 99 ] DEFAULT VALUE #( id = 0 name = 'Inconnu' ) ).Vérification d’existence avec line_exists()
IF line_exists( lt_customers[ id = 2 ] ). WRITE: / 'Le client 2 existe.'.ENDIF.
IF NOT line_exists( lt_customers[ city = 'Stuttgart' ] ). WRITE: / 'Aucun client à Stuttgart.'.ENDIF.Déterminer l’index avec line_index()
DATA(lv_index) = line_index( lt_customers[ id = 2 ] ).
IF lv_index > 0. WRITE: / 'Le client 2 est à la position:', lv_index.ELSE. WRITE: / 'Non trouvé.'.ENDIF.READ TABLE vs. Expression de table
| Aspect | READ TABLE | Expression de table |
|---|---|---|
| Syntaxe | Plus détaillée | Compacte |
| Non trouvé | sy-subrc = 4 | Exception ou OPTIONAL |
| Index disponible | sy-tabix | line_index() |
| Performance | Identique | Identique |
| ASSIGNING | Oui | Oui (avec FIELD-SYMBOL) |
" Expression de table avec symbole de champASSIGN lt_customers[ id = 2 ] TO FIELD-SYMBOL(<fs_cust>).IF sy-subrc = 0. <fs_cust>-city = 'Dresden'.ENDIF.Différence avec LOOP AT
READ TABLE: Lit une seule ligne. Idéal pour les accès ciblés.LOOP AT: Parcourt plusieurs/toutes les lignes séquentiellement.
" Lire une ligne spécifique → READ TABLEREAD TABLE lt_customers INTO ls_customer WITH KEY id = 2.
" Traiter toutes les lignes avec un critère spécifique → LOOP ATLOOP AT lt_customers INTO ls_customer WHERE city = 'Berlin'. " Traiter plusieurs lignesENDLOOP.Conseils de performance
-
Choisir le bon type de table :
- Accès fréquents par clé →
SORTED TABLEouHASHED TABLE - Accès séquentiel →
STANDARD TABLE
- Accès fréquents par clé →
-
BINARY SEARCH uniquement pour les tables triées : Utilisez
SORTavant la recherche binaire :" Incorrect: BINARY SEARCH sans triREAD TABLE lt_unsorted INTO ls_wa WITH KEY field = value BINARY SEARCH. " Dangereux !" Correct: Trier d'abordSORT lt_data BY field.READ TABLE lt_data INTO ls_wa WITH KEY field = value BINARY SEARCH. -
Utiliser les clés secondaires :
DATA: lt_customers TYPE SORTED TABLE OF ty_customerWITH UNIQUE KEY idWITH NON-UNIQUE SORTED KEY by_city COMPONENTS city." Accès rapide via clé secondaireREAD TABLE lt_customers INTO ls_customerWITH KEY by_city COMPONENTS city = 'Berlin'. -
TRANSPORTING NO FIELDS pour les vérifications d’existence : Si on veut seulement vérifier qu’une ligne existe,
TRANSPORTING NO FIELDSest plus efficace. -
Expressions de table avec line_exists() : Pour les vérifications d’existence pures,
line_exists()est élégant et performant.
Remarques importantes / Bonnes pratiques
- Vérifiez toujours
sy-subrcaprès unREAD TABLEavant d’accéder aux données résultantes. - Utilisez
ASSIGNINGpour une meilleure performance et si vous souhaitez modifier la ligne. Alternativement, vous pouvez utiliserMODIFY. - Utilisez
BINARY SEARCHuniquement si la table est garantie triée (voirSORT) – sinon les résultats sont peu fiables. - Pour les accès fréquents par clé, envisagez des tables triées ou de hachage.
- À partir d’ABAP 7.40, les expressions de table sont souvent l’alternative plus élégante et plus courte.
- Pour les tables de hachage,
sy-tabixaprèsREAD TABLEn’est pas défini – ne vous y fiez pas. READ TABLEest pour les tables internes. Pour les tables de base de données, utilisezSELECT SINGLE.