Introduction
Application des techniques et concepts de base
Utilisation des classes locales
Lecture des données de la base de données
Utilisation d'objets de données structurés
Utilisation de tables internes complexes
Implémentation de mises à jour de base de données à l'aide d'objets de gestion
Description du modèle de programmation d'applications ABAP RESTful

Implémentation des instructions SELECT de base

Objectives

After completing this lesson, you will be able to:
  • Décrivez les fonctionnalités de base d'ABAP SQL.
  • Lire des valeurs individuelles à partir de la base de données.

Syntaxe ABAP SQL de base

Structured Query Language (SQL)

Tous les systèmes de base de données relationnelle utilisent une variante de Structured Query Language (SQL) pour vous permettre de les utiliser. Le SQL standard se compose de trois composants principaux :

Langage de manipulation de données (LMD)
DML comprend les instructions dont vous avez besoin pour utiliser les informations dans les tables de base de données. Il s'agit de INSERT, pour ajouter de nouveaux enregistrements, SELECT, pour lire des données, UPDATE, pour modifier des enregistrements existants et DELETE, pour supprimer des contenus de table. Ces instructions sont reflétées dans ABAP sous la forme d'ABAP SQL.
Langage de définition de données (LDD)
Data Definition Language vous fournit des commandes qui vous permettent de créer et de supprimer des tables de base de données et d'autres artefacts de base de données tels que des schémas, des index de table et des vues. Dans un système SAP, vous exécutez ces tâches à l'aide d'éditeurs dédiés d'ADT, et non à l'aide de programmes ABAP. L'éditeur de définitions de table de base de données que nous avons vu précédemment en est un exemple.
Langage de contrôle de données (LCD)
Le langage de contrôle des données est utilisé dans SQL pour restreindre l'accès aux données de la base de données pour un utilisateur particulier. Il n'est pas utilisé dans sa forme classique dans ABAP, car les utilisateurs au niveau de la base de données ne correspondent pas un à un avec les utilisateurs finaux. Par conséquent, ABAP a son propre concept des autorisations.

Architecture ABAP SQL

Dans le passé, les systèmes SAP devaient prendre en charge une série de plateformes de base de données et chaque plate-forme avait une implémentation légèrement différente de la norme SQL. Cela signifiait que chaque plate-forme avait besoin de commandes légèrement différentes pour réaliser une tâche particulière. Pour éviter que le code ABAP ne soit spécifique à la base de données, SAP a inventé ABAP SQL - ou Open SQL tel qu'il a été appelé à l'origine.

Remarque

Le changement de nom Open SQL et ABAP SQL illustre également qu'à partir de la version 7.53, ABAP prend uniquement en charge SAP HANA comme SGBD.

ABAP SQL est un ensemble abstrait de commandes SQL implémentées au niveau ABAP et intégrées au langage ABAP. Au moment de l'exécution, ABAP SQL est traduit en une variante de SQL comprise par la base de données. Cette variante est appelée Native SQL pour la distinguer de ABAP SQL, la variante SQL intégrée à ABAP. La traduction d'ABAP SQL en Native SQL a lieu dans l'interface de base de données, un composant du système ABAP qui se compose d'une partie générale et d'une bibliothèque spécifique à la base de données.

Même si les versions ABAP plus récentes prennent uniquement en charge SAP HANA comme SGBD, SAP a toujours conservé le concept d'ABAP SQL et l'interface de base de données. Cela est dû aux raisons suivantes :

Compatibilité de l'architecture
ABAP SQL et l'interface de base de données font partie intégrante de l'architecture du système.
Compatibilité de code
Le codage ABAP SQL des produits SAP précédents (y compris le développement client) doit s'exécuter sans effets secondaires dans les environnements ABAP modernes uniquement SAP HANA.
Tâches de l'interface de base de données
L'interface de base de données ne se contente pas de traduire des instructions, elle est également responsable de tâches spécifiques ABAP telles que la gestion automatique des mandants.

Lecture d'un enregistrement individuel à partir de la base de données

Instruction SELECT dans ABAP

Pour lire les données de la base de données, vous utilisez l'instruction SELECT.

Lorsque vous écrivez une instruction SELECT dans ABAP SQL, le contrôle syntaxique compare ce que vous avez écrit avec la définition des tables et des vues. Si vous essayez d'adresser des tables, des vues ou des zones qui n'existent pas, une erreur de syntaxe se produit.

La syntaxe de base de l'instruction SELECT contient plusieurs sections, appelées clauses, et suit toujours le modèle de la figure, L'instruction SELECT dans ABAP. Les clauses les plus importantes d'une instruction SELECT sont les suivantes :

FROM
Dans la clause FROM de l'instruction SELECT, vous spécifiez la source de données à partir de laquelle vous souhaitez lire. Il peut s'agir d'une table de base de données ou d'une vue. Les techniques SQL spéciales vous permettent de combiner des données de plusieurs sources dans la même instruction SELECT.
FIELDS
Dans la clause FIELDS de l'instruction SELECT, vous répertoriez les colonnes de la table de base de données que vous souhaitez lire. Les colonnes de la liste doivent être séparées par des virgules. Si vous voulez lire toute la ligne de table, vous pouvez indiquer FIELDS * au lieu d'une liste de colonnes. Cependant, notez que cela peut entraîner beaucoup plus de travail dans la base de données que la simple lecture des colonnes dont vous avez besoin.
WHERE

Dans la clause WHERE, vous pouvez spécifier une condition qui décrit les lignes de la table qui seront lues. Par exemple, la condition WHERE carrier_id = 'LH' signifie que seules les lignes seront lues (dans lesquelles la colonne CARRIER_D contient la valeur LH).

La clause WHERE peut contenir plusieurs conditions liées aux opérateurs AND et OR. Par exemple, WHERE carrier_id = 'LH' et connection_id = '0400' renvoient les données de la liaison aérienne LH 0400. Vous pouvez également annuler des conditions à l'aide de NOT. La clause WHERE est la seule clause facultative. Notez cependant que, sans clause WHERE, vous lisez toutes les données de la table ou, si la table comporte une zone de mandant, toutes les données qui appartiennent au mandant de connexion de l'utilisateur. Les SELECT sans clause WHERE peuvent entraîner de graves problèmes de performance et doivent être évités.

INTO
La clause INTO indique la ou les variables du programme ABAP dans lesquelles les données doivent être placées. Il s'agit normalement d'une structure ou d'une table interne qui doit idéalement avoir la même séquence de composants que la liste de colonnes dans la clause FIELDS.

Remarque

Vous verrez d'autres formes de syntaxe SQL dans ABAP. Celles-ci sont plus anciennes et ont été conservées pour assurer la compatibilité. Vous devez vous habituer à utiliser la syntaxe moderne, car elle fournit bien plus de fonctions et de fonctionnalités que l'ancien formulaire.

La figure, Exemple 1 : lecture d'une zone individuelle d'un enregistrement individuel, illustre une instruction SELECT qui lit une valeur individuelle à partir de la base de données. La clause FROM indique que l'instruction lit à partir de la table de base de données /DMO/CONNECTION. L'option, SINGLE, après le mot-clé SELECT, indique qu'une seule ligne (un seul enregistrement) est lue. Cette ligne est identifiée dans la clause WHERE en fournissant des valeurs de filtre clé pour les zones clés carrier_id et connection_id. Gardez à l'esprit que l'interface de base de données ajoutera un filtre sur le mandant de la zone clé restante.

La clause FIELDS répertorie une seule colonne de la table : colonne AIRPORT_FROM_ID.

La clause INTO doit correspondre au reste de l'instruction. Dans notre exemple, cela spécifie la variable airport_from_id comme objet cible, un objet de données scalaire de type identique à celui du champ de table, airport_from_id.

Remarque

Le signe arobase (@) identifie airport_from_id comme le nom d'un objet de données ABAP. Il est obligatoire pour toutes les variables et constantes que vous utilisez dans une instruction ABAP SQL. Elle est nécessaire pour éviter les ambiguïtés si, par exemple, un objet de données et une zone de table ont le même nom.

La figure, Exemple 2 : lecture de plusieurs zones d'un enregistrement individuel, illustre une instruction SELECT qui lit deux valeurs du même enregistrement de la base de données.

Cette fois-ci, la clause FIELDS répertorie deux colonnes de la table : la colonne AIRPORT_FROM_ID et la colonne AIRPORT_TO_ID.

Pour faire correspondre cela, la clause INTO spécifie les variables airport_from_id et airport_to_id comme objets cibles. Elles sont séparées par une virgule et entourées de deux parenthèses pour indiquer clairement qu'elles forment ensemble la cible de l'instruction SELECT.

Lorsque vous implémentez une instruction SELECT, vous devez toujours tenir compte du fait qu'il n'y a pas de résultat, soit parce que la table de base de données ne contient aucune donnée, soit parce qu'elle ne contient aucune ligne remplissant les conditions de la clause WHERE. Dans l'exemple de la figure ci-dessus, la table de base de données ne contient pas de ligne avec carrier_id = 'XX' et connection_id = '1234'.

ABAP SQL utilise la zone système SY-SUBRC pour indiquer la réussite ou l'échec de l'exécution d'une instruction. La zone système SY-SUBRC est de type nombre entier. La valeur initiale 0 indique toujours une exécution réussie. Si, après une instruction SELECT, SY-SUBRC contient la valeur 4, cela indique que la base de données a renvoyé un résultat vide.

Si la base de données renvoie un résultat vide, ABAP SQL ne touche PAS la variable cible après INTO !

En particulier, la variable cible n'est pas initialisée en cas d'erreur.

Il est recommandé d'analyser le contenu de la zone système sy-subrc immédiatement après chaque instruction SELECT.

Essayer : exemples SELECT

  1. Comme dans le premier exercice de ce cours, créez une nouvelle classe globale qui implémente l'interface IF_OO_ADT_CLASSRUN.
  2. Copiez l'extrait de code suivant dans la partie implémentation de la méthode if_oo_adt_classrun~main( ) :
    Code Snippet
    123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
    DATA airport_from_id TYPE /DMO/airport_from_id. DATA airport_to_id TYPE /DMO/airport_to_id. DATA airports TYPE TABLE OF /DMO/airport_from_id. * Example 1: Single field from Single Record ********************************************************************** SELECT SINGLE FROM /dmo/connection FIELDS airport_from_id WHERE carrier_id = 'LH' AND connection_id = '0400' INTO @airport_from_id. out->write( `----------` ). out->write( `Example 1:` ). out->write( |Flight LH 400 departs from { airport_from_id }.| ). * Example 2: Multiple Fields from Single Record ********************************************************************** SELECT SINGLE FROM /dmo/connection FIELDS airport_from_id, airport_to_id WHERE carrier_id = 'LH' AND connection_id = '0400' INTO ( @airport_from_id, @airport_to_id ). out->write( `----------` ). out->write( `Example 2:` ). out->write( |Flight LH 400 flies from { airport_from_id } to { airport_to_id }| ). * Example 3: Empty Result and sy-subrc ********************************************************************** SELECT SINGLE FROM /dmo/connection FIELDS airport_from_id WHERE carrier_id = 'XX' AND connection_id = '1234' INTO @airport_from_id. IF sy-subrc = 0. out->write( `----------` ). out->write( `Example 3:` ). out->write( |Flight XX 1234 departs from { airport_from_id }.| ). ELSE. out->write( `----------` ). out->write( `Example 3:` ). out->write( |There is no flight XX 1234, but still airport_from_id = { airport_from_id }!| ). ENDIF.
  3. Appuyez sur CTRL + F3 pour activer la classe et SUR F9 pour l'exécuter en tant qu'application console.
  4. Analysez la sortie de la console. Déboguer le programme, jouer avec le code source pour se familiariser avec les concepts.

Lire les données d'une table de base de données

Dans cet exercice, vous étendez votre classe locale avec des attributs pour l'aéroport de départ et l'aéroport d'arrivée et vous lisez les valeurs de ces attributs à partir d'une table de base de données.

Modèle :

  • /LRN/CL_S4D400_CLS_CONSTRUCTOR (classe globale)

Solution :

  • /LRN/CL_S4D400_DBS_SELECT (classe globale)

Tâche 1: Copier modèle

Copiez la classe de modèle. Vous pouvez également copier votre solution de l'exercice précédent.

Étapes

  1. Copiez la classe /LRN/CL_S4D400_CLS_CONSTRUCTOR dans une classe de votre propre package (nom proposé : ZCL_##_SELECT, ## correspondant à votre numéro de groupe).

    1. Ouvrez le code source de la classe globale /LRN/CL_S4D400_CLS_CONSTRUCTOR.

    2. Liez la vue Explorateur de projets à l'aide de l'éditeur.

    3. Dans la vue Explorateur de projets, cliquez avec le bouton droit de la souris sur la classe /LRN/CL_S4D400_CLS_CONSTRUCTOR pour ouvrir le menu contextuel.

    4. Dans le menu contextuel, sélectionnez Dupliquer ....

    5. Saisissez le nom de votre package dans la zone Package. Dans la zone Nom, saisissez le nom ZCL_##_SELECT, où ## représente votre numéro de groupe.

    6. Ajustez la description et cliquez sur Suivant.

    7. Confirmez l'ordre de transport et cliquez sur Terminer.

Tâche 2: Déclarer attributs supplémentaires

Étendez la classe locale lcl_connection avec les attributs d'instance privés airport_from_id et airport_to_id. Ajoutez une sortie pour les nouveaux attributs à l'implémentation de la méthode get_output.

Remarque

Les nouveaux attributs ne sont pas encore renseignés. Afin de les remplir, nous allons ajouter une instruction SELECT au constructeur dans l'une des tâches suivantes de cet exercice.

Étapes

  1. Passez à la classe locale lcl_connection.

    1. Dans la classe globale, sélectionnez Types locaux.

  2. Ajoutez les attributs privés suivants à la définition de classe :

    attributs

    Nom de l'attributPérimètreType de données
    airport_from_idInstance/DMO/AIRPORT_FROM_ID
    airport_to_idInstance/DMO/AIRPORT_TO_ID
    1. Adaptez le code comme suit :

      Code Snippet
      12345678910
      PRIVATE SECTION. DATA carrier_id TYPE /dmo/carrier_id. DATA connection_id TYPE /dmo/connection_id. DATA airport_from_id TYPE /dmo/airport_from_id. DATA airport_to_id TYPE /dmo/airport_to_id. ENDCLASS.
  3. Étendez l'implémentation de la méthode get_output. Ajoutez d'autres modèles de chaîne au paramètre de retour r_output. Intégrez les nouveaux attributs en tant qu'expressions dans les modèles de chaîne.

    1. Naviguez vers l'implémentation de la méthode get_output.

    2. Adaptez le code comme suit :

      Code Snippet
      1234567
      APPEND |--------------------------------| TO r_output. APPEND |Carrier: { carrier_id }| TO r_output. APPEND |Connection: { connection_id }| TO r_output. APPEND |Departure: { airport_from_id }| TO r_output. APPEND |Destination: { airport_to_id }| TO r_output.
  4. Activez la classe. Exécutez-la et analysez la sortie de la console.

    1. Appuyez sur Ctrl + F3 pour activer la classe.

    2. Appuyez sur F9 pour exécuter la classe.

Tâche 3: Analyser la table de base de données

Analysez la définition de la table de base de données /DMO/CONNECTION.

Étapes

  1. Ouvrez l'objet de développement qui contient la définition de la table de base de données /DMO/CONNECTION.

    1. Dans la barre d'outils Eclipse, sélectionnez Ouvrir ABAP Development Object ou appuyez sur Ctrl + Maj + A.

    2. Dans la zone de saisie, saisissez /dmo/con comme chaîne de recherche.

    3. Dans la liste des postes de comparaison, cliquez sur /DMO/CONNECTION (table de base de données) et cliquez sur OK.

  2. Ouvrez les informations sur l'élément (F2) pour la table de base de données /DMO/CONNECTION.

    1. Cliquez sur /dmo/connection après le mot-clé define table et appuyez sur F2 pour afficher les informations de l'élément.

Tâche 4: Lire données de la base de données

Dans le constructeur de méthode de la classe locale lcl_connection, implémentez une instruction SELECT qui lit les valeurs des nouveaux attributs de la table de base de données /DMO/CONNECTION.

Étapes

  1. Retournez à la classe locale lcl_connection dans votre classe globale.

    1. Dans la vue de l'éditeur d'Eclipse, ouvrez l'onglet ZCL_##_SELECT.

    2. Dans la classe globale, sélectionnez Types locaux.

  2. Naviguez vers l'implémentation du constructeur de méthode.

    1. Recherchez la ligne de code METHOD constructor..

  3. Après l'instruction ENDIF., ajoutez une instruction SELECT qui lit un enregistrement individuel de la table de base de données /DMO/CONNECTION.

    1. Adaptez le code comme suit :

      Code Snippet
      123456789
      IF i_carrier_id IS INITIAL OR i_connection_id IS INITIAL. RAISE EXCEPTION TYPE cx_abap_invalid_value. ENDIF. SELECT SINGLE FROM /dmo/connection
  4. Implémentez la clause FIELDS. Lisez les zones de table airport_from_id et airport_to_id.

    Astuce

    Utilisez la saisie semi-automatique (Ctrl + Espace) pour saisir les noms des zones.
    1. Après FROM /DMO/CONNECTION saisissez FIELDS.

    2. Après un vide, appuyez sur Ctrl + Espace et sélectionnez airport_from_id.

    3. Après une virgule et un espace, appuyez à nouveau sur Ctrl + Espace et sélectionnez airport_to_id.

    4. La clause FIELDS complète doit ressembler à ceci :

      Code Snippet
      123
      FIELDS airport_from_id, airport_to_id
  5. Implémentez la condition WHERE. Limitez toutes les zones clés de la table de base de données (à l'exception de la zone client) avec les valeurs des paramètres d'importation i_carrier_id et i_connection_id. N'oubliez pas d'ignorer les paramètres avec le préfixe @.

    Astuce

    Utilisez la saisie semi-automatique (Ctrl + Espace) pour saisir les noms des éléments et des paramètres.
    1. Ajoutez le code suivant après la clause FIELDS :

      Code Snippet
      1234
      WHERE carrier_id = @i_carrier_id AND connection_id = @i_connection_id
  6. Implémentez la clause INTO. Stockez le résultat SELECT dans les attributs airport_from_id et airport_to_id. N'oubliez pas d'échapper aux attributs avec le préfixe @.

    Astuce

    Utilisez la saisie semi-automatique (Ctrl + Espace) pour saisir les noms des attributs.
    1. Adaptez le code comme suit :

      Code Snippet
      123456
      WHERE carrier_id = @i_carrier_id AND connection_id = @i_connection_id INTO ( @airport_from_id, @airport_to_id ).
    2. L'instruction SELECT complète doit ressembler à ceci :

      Code Snippet
      12345678
      SELECT SINGLE FROM /dmo/connection FIELDS airport_from_id, airport_to_id WHERE carrier_id = @i_carrier_id AND connection_id = @i_connection_id INTO ( @airport_from_id, @airport_to_id ).
  7. Implémentez la gestion des erreurs après l'instruction SELECT. Vérifiez le contenu de la zone système sy-subrc. Si elle n'est pas égale à zéro, déclenchez l'exception CX_ABAP_INVALID_VALUE.

    1. Ajoutez le code suivant après l'instruction SELECT :

      Code Snippet
      12345
      IF sy-subrc <> 0. RAISE EXCEPTION TYPE cx_abap_invalid_value. ENDIF.
  8. Activez la classe. Exécutez-la et analysez la sortie de la console. Vérifiez que l'édition des nouveaux attributs affiche des données.

    1. Appuyez sur Ctrl + F3 pour activer la classe.

    2. Appuyez sur F9 pour exécuter la classe.