ABAP – 7ème partie

Hey hey, de retour avec l’ABAP ! Et cette fois, pour parler du traitement des bases de données.

Le langage ABAP est un langage orienté base de données. C’est-à-dire que la plupart des opérations sont liées de près ou de loin aux données stockées en base. De fait, beaucoup d’instructions ABAP sont dédiées à ces traitements.

Remarque : cet article ne traitera pas particulièrement des requêtes en base de données, on n’est pas là pour faire du SQL…

Base de données et ABAP

Un objet très utilisé en ABAP est la table interne. Une table interne, c’est une table de base de données, mais en variable. Dans d’autres langages, sauf erreur, on parlerait de collection d’Array.
Une table interne peut être utilisée en retour d’un SELECT sur une (ou plusieurs) table(s), mais également dans un UPDATE par exemple.

En effet, comme je le disais, l’idée avec l’ABAP, c’est que l’on manipule des données issues d’une base (SAP propose une couche d’abstraction au-dessus du SGBD). Et ces données, à l’exécution, sont représentées par des tables internes.

Exemple

Supposons une table de la structure suivante : champ1, champ2, …, champN. Appelons cette table : dummy_table.
Pour requêter dans cette table, il est nécessaire de déclarer une variable table interne dont le type correspondra (dans l’idéal, mais ce n’est pas obligé) à celui de la table. Si l’on souhaite sélectionner tous les champs de la table, il suffira de déclarer la table interne comme étant du type de la table en base :
DATA : wt_table_interne TYPE STANDARD TABLE OF dummy_table WITH DEFAULT KEY.

Explication de texte :
– DATA : annonce la déclaration de variables ;
– TYPE : ce qui suit est le type de la variable dont le nom précède ;
– STANDARD TABLE : la table interne sera de type standard c’est-à-dire que par défaut, elle n’est pas triée ;
– OF dummy_table : la structure (= les champs) de la table interne reprend celle de la table dummy_table ;
– WITH DEFAULT KEY : c’est facultatif mais les outils de contrôle du code fournis par SAP le réclament.

Ensuite, il suffit d’effectuer un petit SELECT :
SELECT * INTO TABLE wt_table_interne FROM dummy_table.

L’ensemble du contenu de la table sera transféré dans la variable wt_table_interne. Évidemment, une clause WHERE peut être ajoutée à la requête pour filtrer les résultats.

Les instructions de manipulation des tables internes

Une fois notre table interne alimentée (notez qu’il existe d’autres moyens d’alimenter une table interne), il est possible de manipuler son contenu.

  • READ TABLE : cette instruction permet de lire un enregistrement de la table interne. On lui précise la table interne et les critères de recherche. Typiquement, ces critères seront soit directement le n° de l’enregistrement, soit avec une pseudo clause WHERE qui n’accepte que des égalités dans les conditions logiques. Exemple :
    READ TABLE wt_table_interne WITH KEY champ1 = 'valeur' ASSIGNING .
    Remarque : ASSIGNING permet de créer un pointeur sur la ligne de la table interne.
    Autres remarques : la volumétrie étant souvent énorme, le but est d’éviter au système de parcourir toute la table interne à la recherche de l’enregistrement demandé. Pour améliorer les temps de traitement, il est recommandé de trier la table interne (ou d’utiliser un type de table interne SORTED voire HASHED) et d’ajouter les mots-clés BINARY SEARCH à l’instruction READ TABLE afin que la recherche soit dichotomique.
  • LOOP : comme son nom l’indique, cette instruction va effectuer une boucle séquentielle sur les entrées de la table interne. Il est possible d’ajouter une clause WHERE (de la même façon que pour une requête SQL) pour filtrer certains enregistrements. À noter que cette clause WHERE est évaluée une seule fois, et non à chaque tour de boucle. C’est plus performant, mais les modifications effectuées sur la table interne en cours de boucle ne seront pas prises en compte dans le WHERE.
  • INSERT : permet d’insérer une ou plusieurs lignes dans la table interne.
  • MODIFY/DELETE : les noms sont explicites.
  • SORT : permet de trier la table interne selon plusieurs champs, en mixant les ordres de tri. Par exemple :
    SORT wt_table_interne BY champ1 ASCENDING champ2 DESCENDING.

Il existe d’autres instructions, mais je ne répertorie ici que les plus classiques.

Les types de tables internes

Comme dit un peu plus haut, il existe plusieurs types de tables internes, dont le choix aura un impact sur les accès et les temps de traitements.

Le type STANDARD crée une simple table interne sans clé. Elle peut être triée à l’exécution sans restriction et sans obligation d’unicité. Ce type de table est à utiliser sur une table susceptible d’être triée à plusieurs reprises et différemment au cours du traitement par exemple, ou pour des tables dont aucun critère de tri n’est nécessaire (donc peu ou aucun accès direct sur la table, c’est-à-dire pas de READ TABLE filtré). Ou encore sur les tables internes qui sont beaucoup modifiées à l’exécution.

Le type SORTED crée une table interne triée (selon une clé unique ou non). Elle ne pourra pas être triée durant l’exécution. Il est impossible également de la trier de façon descendante. Avec de telles tables internes, les temps accès non séquentiels peuvent être améliorés, en utilisant la recherche dichotomique (implicite sur ce type de table) lors des READ TABLE ou des LOOP. À utiliser avec parcimonie cependant car chaque insertion dans la table entraîne un nouveau calcul du tri.

Enfin, le type HASHED crée une table interne de hashage. Cela signifie que chaque enregistrement est accédé en mémoire selon sa clé, qui doit être unique. Le temps d’accès à un enregistrement d’une table interne de hashage est constant, peu importe la volumétrie de la table interne, mais l’algorithme de hashage a un coût qui n’est négligeable que passé une forte volumétrie. Ce type de table est donc à réserver aux tables internes très grosses et dont l’accès est principalement unique (READ TABLE, par opposition avec les opérations de modification, suppression et les boucles).

Tables internes et base de données

Pour terminer, abordons la relation entre les tables internes et les tables de la base de données.
On a vu plus haut que le résultat d’un SELECT simple peut être récupéré dans une table interne. C’est aussi le cas avec les SELECT plus compliqués (non *, avec jointures…). Il suffit que la structure (les champs) requêtée corresponde à la structure de la table interne.
Pour déclarer la table interne, il est possible de faire comme précédemment, mais une méthode plus souple propose de lister simplement tous les champs dont on aura besoin au cours du traitement.
Une utilisation relativement puissante permet de requêter une table (ou plusieurs si jointure) avec en clause WHERE une table interne. On pourrait donc envisager de sélection dans la table des clients les nom et prénom de tous les clients dont le numéro (identifiant) est présent dans une table interne. Cela revient à une jointure entre une table interne et une table de la base de données.

De plus, les tables internes peuvent être utilisées pour les mises à jour en masse de la base (insertion, modification et suppression). La condition ici étant que cette fois la structure de la table interne doit être celle de la table visée. Les traitements sont plus rapides que si l’on utilisait une méthode unitaire, l’inconvénient étant qu’en cas de problème, on ne sait pas quel enregistrement de la table interne n’a pu être mis à jour en base de données.

Une toute dernière remarque : la connexion à la base de données est implicite et n’est donc pas à gérer en ABAP.

Ce sera tout pour le moment, je pense en avoir dit pas mal, j’espère avoir été clair. À bientôt pour de nouvelles aventures ABAP !

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *