Analyse et test du code
Utilisation correcte des types de données et des conversions de types
Traitement des zones de caractères
Utilisation du Pushdown de code dans ABAP SQL
Amélioration de la performance des tables internes
Implémentation des contrôles des autorisations
Conception d'un code orienté objet efficace
Définition et utilisation des classes d'exception
Ajout de documentation au code ABAP

Utilisation de fonctions intégrées spéciales dans ABAP SQL

Objectives

After completing this lesson, you will be able to:
  • Traitez les dates, heures et horodatages dans la base de données.
  • Utilisez des fonctions de conversion intégrées.

Fonctions de traitement des dates, heures et horodatages

Si vous voulez stocker des informations de date dans une zone de base de données, vous avez le choix entre deux types :

  • DATS archive la date telle qu'elle est traitée dans ABAP. Cela signifie que la date est enregistrée sous la forme d'un caractère de longueur 8 au format "AAAAMMJJ".
  • DATN stocke les informations dans le type de date de la base de données. Lors de la lecture des informations de la base de données avec ABAP SQL, elles sont automatiquement reconverties au format à 8 chiffres.

La même différence existe entre les types TIMS et TIMN.

Si vous voulez enregistrer des informations d'horodatage dans une zone de base de données, vous avez le choix entre trois types :

  • HORODATAGE stocke les informations sous forme de nombre sans décimales, les chiffres du nombre représentant l'année, le mois, le jour, les heures, les minutes et les secondes.
  • TIMESTAMPL est le même que TIMESTAMP, mais stocke en plus jusqu'à 7 décimales ce qui correspond à une précision de 100 nanosecondes.
  • UTCLONG a la même précision que TIMESTAMPL.

Fonctions SQL pour date, heure et horodatage

ABAP SQL offre une grande variété de fonctions intégrées pour les informations de date, d'heure et d'horodatage. Il existe des fonctions pour vérifier si le contenu d'une zone est valide, des fonctions pour les calculs ou des fonctions pour extraire certaines informations d'un argument d'entrée. Certaines de ces fonctions sont répertoriées ici. Vous trouverez une liste complète dans la documentation ABAP.

Certaines fonctions sont spécifiques au type.

Les autres fonctions sont génériques. Ils peuvent gérer l'entrée de différents types. La fonction IS_VALID, par exemple, peut contrôler la validité d'une date, d'une date ou d'un horodatage. Il accepte les deux formats de date (DATS et DATN) et les deux formats d'heure (TIMS et TIMN). Cependant, pour les horodatages, seul le type UTCLONG est pris en charge.

Dans certains cas, vous pouvez choisir entre une fonction spécifique au type et une fonction générique. Pour une zone de type DATS, par exemple, vous pouvez utiliser DATS_IS_VALID( ) ou IS_VALID( ). Vous devez préférer les fonctions génériques les plus récentes.

Remarque

Actuellement, les fonctions génériques ne prennent pas en charge les horodatages de type TIMESTAMP et TIMESTAMPL. Pour ces types, vous devez utiliser les fonctions spécifiques au type commençant par TSTMP_ ou TSTMPL_.

Voici un exemple d'utilisation de fonctions génériques avec des informations de type date. Comme la plupart des autres expressions SQL, vous pouvez également utiliser les fonctions de la clause WHERE-clause. Ici, nous limitons la sélection aux déplacements qui dépassent 10 jours.

Remarque

La fonction IS_VALID( ) n'est pas une fonction booléenne réelle. Retourne la valeur entière 1 pour vrai et 0 pour faux.

Essayer de sortir : traitement de la date

  1. 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
    12345678910111213141516171819202122232425
    SELECT FROM /dmo/travel FIELDS begin_date, end_date, is_valid( begin_date ) AS valid, add_days( begin_date, 7 ) AS add_7_days, add_months( begin_date, 3 ) AS add_3_months, days_between( begin_date, end_date ) AS duration, weekday( begin_date ) AS weekday, extract_month( begin_date ) AS month, dayname( begin_date ) AS day_name WHERE customer_id = '000001' AND days_between( begin_date, end_date ) > 10 INTO TABLE @DATA(result). out->write( EXPORTING data = result name = 'RESULT' ).
  3. Sélectionnez CTRL + F3 pour activer la classe et F9 pour l'exécuter en tant qu'application de console.
  4. Analysez la sortie de la console.
  5. Positionnez le curseur sur l'une des fonctions de traitement des dates (par exemple, jour de la semaine) et sélectionnez F1 pour ouvrir la documentation.
  6. Recherchez d'autres fonctions de traitement des dates dans la documentation et essayez-les pour vous familiariser avec leurs possibilités.

Fonctions de conversion

Certaines fonctions de conversion ABAP SQL

Toutes les conversions de type ne peuvent pas être gérées par l'expression CAST. Pour certaines conversions, ABAP SQL propose des fonctions de conversion spécifiques, comme illustré dans la figure ci-dessous.

Exemple : la fonction SQL DATS_FROM_DATN, qui effectue la conversion de DATN, la représentation de date spécifique à la base de données, en DATS, le format de date de type caractère spécifique ABAP. La fonction SQL DATS_TO_DATN( ) effectue la conversion dans l'autre sens.

Les fonctions TSTMP_TO_DATS( ) et TSTMP_TO_TIMS( ) convertissent un horodatage en un champ de date et un champ d'heure, respectivement. Notez que ces fonctions sont disponibles uniquement pour les horodatages au format technique DEC( 15, 0). D'autres formats d'horodatage doivent être convertis avant de pouvoir servir de saisie pour ces fonctions. La fonction DATS_TIMS_TO_TSTMP combine une information de date et d'heure en un seul horodatage.

Un groupe spécial de fonctions de conversion vous permet d'effectuer des conversions entre différentes unités de mesure et devises. La fonction UNIT_CONVERSION( ) convertit une quantité d'une unité source en unité cible, par exemple, une distance en kilomètres par rapport à la même distance en miles. La fonction CURRENCY_CONVERSION( ) convertit un montant dans une devise dans le même montant dans une autre devise à une date de reporting spécifique.

Remarque

Pour que CURRENCY_CONVERSION( ) fonctionne correctement, les taux de change dépendants du temps doivent être disponibles dans la base de données de votre système. Pour en savoir plus, consultez la documentation du système SAP.

Exemple : fonction SQL pour la conversion de l'horodatage

Cet exemple lit un horodatage UTC de la table /DMO/TRAVEL (zone LASTCHANGEDAT) et le convertit en date et heure dans le fuseau horaire "EST".

L'horodatage est archivé dans la table de base de données comme type TIMESTAMPL, c'est-à-dire avec 7 décimales. Cela signifie qu'il doit être converti en un court horodatage sans décimales pour le rendre compatible avec le paramètre d'entrée TSTMP des fonctions SQL. Le littéral "EST" doit également être converti pour être compatible avec le paramètre d'entrée TZONE.

Remarque

Il existe un décalage de 4 heures entre le temps universel et l'heure normale de l'Est.

Exemple : fonction SQL pour la conversion d'unités

Dans cet exemple, les informations de distance des liaisons aériennes sont converties en miles (MI), tandis que dans la base de données, les informations sont stockées en kilomètres (KM).

Comme la zone de table DISTANCE est définie avec le type INT4 au lieu du type QUAN, elle doit être convertie pour correspondre au type du paramètre d'entrée QUANTITY.

Le littéral "MI" doit également être converti car il est de type CHAR(2) et non de type "UNIT".

Remarque

L'exemple fournit uniquement les trois paramètres obligatoires de UNIT_CONVERSION( ). Vous trouverez une liste des paramètres facultatifs et leur signification dans la documentation ABAP.

Dans cet exemple, le prix total d'un déplacement est converti dans la devise cible Euro. La fonction CURRENCY_CONVERSION est fournie avec le montant (zone TOTAL_PRICE), la devise source (zone CURRENCY_CODE), la devise cible (littéral "EUR") et la date du cours de conversion (variable ABAP TODAY). Avant l'instruction SELECT, la variable TODAY est renseignée dans un appel de méthode avec la date système.

Remarque

L'exemple fournit uniquement les quatre paramètres obligatoires de CURRENCY_CONVERSION( ). Vous trouverez une liste des paramètres facultatifs et leur signification dans la documentation ABAP.

Essayer : fonctions de conversion

  1. 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
    12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
    SELECT FROM /dmo/travel FIELDS lastchangedat, CAST( lastchangedat AS DEC( 15,0 ) ) AS latstchangedat_short, tstmp_to_dats( tstmp = CAST( lastchangedat AS DEC( 15,0 ) ), tzone = CAST( 'EST' AS CHAR( 6 ) ) ) AS date_est, tstmp_to_tims( tstmp = CAST( lastchangedat AS DEC( 15,0 ) ), tzone = CAST( 'EST' AS CHAR( 6 ) ) ) AS time_est WHERE customer_id = '000001' INTO TABLE @DATA(result_date_time). out->write( EXPORTING data = result_date_time name = 'RESULT_DATE_TIME' ). ********************************************************************* DATA(today) = cl_abap_context_info=>get_system_date( ). SELECT FROM /dmo/travel FIELDS total_price, currency_code, currency_conversion( amount = total_price, source_currency = currency_code, target_currency = 'EUR', exchange_rate_date = @today ) AS total_price_EUR WHERE customer_id = '000001' AND currency_code <> 'EUR' INTO TABLE @DATA(result_currency). out->write( EXPORTING data = result_currency name = 'RESULT__CURRENCY' ). ********************************************************************** SELECT FROM /dmo/connection FIELDS distance, distance_unit, unit_conversion( quantity = CAST( distance AS QUAN ), source_unit = distance_unit, target_unit = CAST( 'MI' AS UNIT ) ) AS distance_MI WHERE airport_from_id = 'FRA' INTO TABLE @DATA(result_unit). out->write( EXPORTING data = result_unit name = 'RESULT_UNIT' ).
  3. Sélectionnez CTRL + F3 pour activer la classe et F9 pour l'exécuter en tant qu'application de console.
  4. Analysez la sortie de la console.

Utilisation de fonctions intégrées spéciales dans ABAP SQL

Dans cet exercice, vous poussez le calcul de la durée du vol et la conversion de devise vers la base de données.

Modèle :

  • /LRN/CL_S4D401_DBS_PUSH_DOWN (classe globale)

Solution :

  • /LRN/CL_S4D401_DBS_FUNCTIONS (classe globale)

Tâche 1: Copier modèle (facultatif)

Copiez la classe de modèle /LRN/CL_S4D401_DBS_PUSH_DOWN. Si vous avez terminé l'exercice précédent, vous pouvez ignorer cette tâche et continuer à modifier votre classe ZCL_##_SOLUTION.

Étapes

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

    1. Dans l'explorateur de projets, cliquez avec le bouton droit de la souris sur la classe /LRN/CL_S4D401_DBS_PUSH_DOWN pour ouvrir le menu contextuel.

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

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

    4. Cliquez sur Next.

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

  2. Activez la copie.

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

Tâche 2: Calculer avec horodatages

Dans la classe locale LCL_PASSENGER_FLIGHT, ajustez l'implémentation de la méthode CLASS_CONSTRUCTOR. Déplacez le calcul de la durée de vol dans la liste de zones de l'instruction SELECT et archivez le résultat dans la colonne de durée de la table interne connections_buffer.

Étapes

  1. Dans la classe locale LCL_PASSENGER_FLIGHT, naviguez jusqu'à l'implémentation de la méthode CLASS_CONSTRUCTOR.

    1. Pour cette étape, procédez comme vous l'avez fait précédemment.

  2. À la fin de la liste de zones de l'instruction SELECT, ajoutez un appel à une fonction SQL appropriée qui calcule la différence en secondes entre deux horodatages.

    1. Adaptez le code comme suit :

      ABAP
      12345678910111213
      SELECT FROM /lrn/connection AS c LEFT OUTER JOIN /lrn/airport AS f ON c~airport_from_id = f~airport_id LEFT OUTER JOIN /lrn/airport AS t ON c~airport_to_id = t~airport_id FIELDS carrier_id, connection_id, airport_from_id, airport_to_id, departure_time, arrival_time, f~timzone AS timezone_from, t~timzone AS timezone_to, tstmp_seconds_between( ) INTO TABLE @connections_buffer.
  3. Comme premier argument (paramètre tstmp1), appelez une fonction SQL appropriée qui calcule un horodatage basé sur la date actuelle, l'heure de départ et le fuseau horaire de l'aéroport de départ.

    Astuce

    Vous devez déplacer l'appel vers la méthode fonctionnelle cl_abap_context_info=>get_system_date avant l'instruction SELECT afin de pouvoir accéder à la date actuelle dans l'instruction SELECT.
    1. Adaptez le code comme suit :

      ABAP
      1234567891011121314151617181920
      DATA(today) = cl_abap_context_info=>get_system_date( ). SELECT FROM /lrn/connection AS c LEFT OUTER JOIN /lrn/airport AS f ON c~airport_from_id = f~airport_id LEFT OUTER JOIN /lrn/airport AS t ON c~airport_to_id = t~airport_id FIELDS carrier_id, connection_id, airport_from_id, airport_to_id, departure_time, arrival_time, f~timzone AS timezone_from, t~timzone AS timezone_to, tstmp_seconds_between( tstmp1 = dats_tims_to_tstmp( date = @today, time = c~departure_time, tzone = f~timzone ), ) INTO TABLE @connections_buffer.
  4. Appelez la même fonction SQL pour calculer l'horodatage d'arrivée correspondant comme deuxième argument (paramètre tstmp2).

    1. Adaptez le code comme suit :

      ABAP
      123456789101112131415161718192021222324
      DATA(today) = cl_abap_context_info=>get_system_date( ). SELECT FROM /lrn/connection AS c LEFT OUTER JOIN /lrn/airport AS f ON c~airport_from_id = f~airport_id LEFT OUTER JOIN /lrn/airport AS t ON c~airport_to_id = t~airport_id FIELDS carrier_id, connection_id, airport_from_id, airport_to_id, departure_time, arrival_time, f~timzone AS timezone_from, t~timzone AS timezone_to, tstmp_seconds_between( tstmp1 = dats_tims_to_tstmp( date = @today, time = c~departure_time, tzone = f~timzone ), tstmp2 = dats_tims_to_tstmp( date = @today, time = c~arrival_time, tzone = t~timzone ) ) INTO TABLE @connections_buffer.
  5. Comme nous voulons que la durée soit exprimée en minutes et non en secondes, divisez le nombre de secondes par 60.

    Astuce

    Utilisez une fonction SQL arithmétique appropriée qui renvoie le résultat de la division sous forme d'entier.
    1. Adaptez le code comme suit :

      ABAP
      1234567891011121314151617181920212223242526
      DATA(today) = cl_abap_context_info=>get_system_date( ). SELECT FROM /lrn/connection AS c LEFT OUTER JOIN /lrn/airport AS f ON c~airport_from_id = f~airport_id LEFT OUTER JOIN /lrn/airport AS t ON c~airport_to_id = t~airport_id FIELDS carrier_id, connection_id, airport_from_id, airport_to_id, departure_time, arrival_time, f~timzone AS timezone_from, t~timzone AS timezone_to, div( tstmp_seconds_between( tstmp1 = dats_tims_to_tstmp( date = @today, time = c~departure_time, tzone = f~timzone ), tstmp2 = dats_tims_to_tstmp( date = @today, time = c~arrival_time, tzone = t~timzone ) ), 60 ) INTO TABLE @connections_buffer.
  6. Enfin, indiquez un nom d'alias pour l'expression complète (nom suggéré : durée).

    1. Adaptez le code comme suit :

      ABAP
      1234567891011121314151617181920212223242526
      DATA(today) = cl_abap_context_info=>get_system_date( ). SELECT FROM /lrn/connection AS c LEFT OUTER JOIN /lrn/airport AS f ON c~airport_from_id = f~airport_id LEFT OUTER JOIN /lrn/airport AS t ON c~airport_to_id = t~airport_id FIELDS carrier_id, connection_id, airport_from_id, airport_to_id, departure_time, arrival_time, f~timzone AS timezone_from, t~timzone AS timezone_to, div( tstmp_seconds_between( tstmp1 = dats_tims_to_tstmp( date = @today, time = c~departure_time, tzone = f~timzone ), tstmp2 = dats_tims_to_tstmp( date = @today, time = c~arrival_time, tzone = t~timzone ) ), 60 ) AS duration INTO TABLE @connections_buffer.
  7. Maintenant que vous avez correctement déplacé le calcul dans l'instruction SELECT, supprimez ou commentez la boucle complète sur la table interne connections_buffer.

    1. Marquez l'instruction LOOP, l'instruction ENDLOOP et toutes les lignes de code intermédiaires, puis appuyez sur Ctrl + < pour insérer un caractère de commentaire avant chaque ligne de code.

Tâche 3: Convertir devises

Dans la classe locale LCL_PASSENGER_FLIGHT, ajustez l'implémentation des méthodes CONSTRUCTOR et GET_FLIGHTS_BY_CARRIER. Déplacez la conversion de devise dans la liste de zones des instructions SELECT.

Étapes

  1. Dans la classe locale LCL_PASSENGER_FLIGHT, naviguez jusqu'à l'implémentation de la méthode CONSTRUCTOR.

    1. Pour cette étape, procédez comme vous l'avez fait précédemment.

  2. Recherchez l'appel de méthode qui convertit le prix du vol en code de devise enregistré dans la devise de l'attribut. Analysez-le, puis ajoutez des signes de commentaire au début des lignes de code.

    1. La conversion de devise est effectuée en appelant la méthode convert_to_local_currency de la classe globale cl_exchange_rates.

    2. Pour commenter l'appel de la méthode, marquez l'instruction TRY, l'instruction ENDTRY et toutes les lignes de code entre elles et appuyez sur Ctrl + <.

  3. Étant donné que l'attribut de prix n'est plus renseigné via l'appel de méthode cl_exchange_rates=>convert_to_local_currency, affectez la valeur de l'élément de prix de la structure flight_raw directement à l'attribut de prix. Ajoutez cette affectation directement après l'appel de méthode que vous venez de commenter.

    Remarque

    Dans les étapes suivantes, vous allez vous assurer que flight_raw-price contient le prix du vol converti.
    1. Adaptez le code comme suit :

      ABAP
      1234567891011121314
      * TRY. * cl_exchange_rates=>convert_to_local_currency( * EXPORTING * date = me->flight_date * foreign_amount = flight_raw-price * foreign_currency = flight_raw-currency_code * local_currency = currency * IMPORTING * local_amount = me->price ). * CATCH cx_exchange_rates. * CLEAR price. * ENDTRY. price = flight_raw-price.
  4. Faites défiler jusqu'à l'instruction SELECT SINGLE. Dans la liste de zones, remplacez la zone de table PRICE par un appel de la fonction SQL pour les conversions de devises.

    1. Adaptez le code comme suit :

      ABAP
      123456789101112
      SELECT SINGLE FROM /lrn/passflight FIELDS plane_type_id, seats_max, seats_occupied, seats_max - seats_occupied AS seats_free, * price, currency_conversion( ) AS price, currency_code WHERE carrier_id = @i_carrier_id AND connection_id = @i_connection_id AND flight_date = @i_flight_date INTO CORRESPONDING FIELDS OF @flight_raw.
  5. Indiquez les quatre paramètres obligatoires de la fonction SQL. Comme date du cours de conversion, utilisez la date du vol (zone de table flight_date), comme montant et devise source, utilisez les zones de table prix et devise et comme devise cible, utilisez l'attribut devise.

    1. Adaptez le code comme suit :

      ABAP
      1234567891011121314151617
      SELECT SINGLE FROM /lrn/passflight FIELDS plane_type_id, seats_max, seats_occupied, seats_max - seats_occupied AS seats_free, * price, currency_conversion( amount = price, source_currency = currency_code, target_currency = @currency, exchange_rate_date = flight_date ) AS price, currency_code WHERE carrier_id = @i_carrier_id AND connection_id = @i_connection_id AND flight_date = @i_flight_date INTO CORRESPONDING FIELDS OF @flight_raw.
  6. Renseignez le paramètre facultatif on_error avec une valeur appropriée pour obtenir le même comportement qu'auparavant.

    Astuce

    Reportez-vous à la documentation de la fonction SQL pour connaître les valeurs possibles pour le paramètre et leur signification.
    1. Vous trouverez les valeurs autorisées comme composants de la constante structurée c_on_error dans la classe globale SQL_CURRENCY_CONVERSION.

    2. Adaptez le code comme suit :

      ABAP
      12345678910111213141516171819
      SELECT SINGLE FROM /lrn/passflight FIELDS plane_type_id, seats_max, seats_occupied, seats_max - seats_occupied AS seats_free, * price, currency_conversion( amount = price, source_currency = currency_code, target_currency = @currency, exchange_rate_date = flight_date, on_error = @sql_currency_conversion=>c_on_error-set_to_null ) AS price, currency_code WHERE carrier_id = @i_carrier_id AND connection_id = @i_connection_id AND flight_date = @i_flight_date INTO CORRESPONDING FIELDS OF @flight_raw.
  7. Dans la liste de zones, remplacez la zone de table currency_code par l'attribut de devise.

    1. Ajustement du code comme suit :

      ABAP
      1234567891011121314151617181920
      SELECT SINGLE FROM /lrn/passflight FIELDS plane_type_id, seats_max, seats_occupied, seats_max - seats_occupied AS seats_free, * price, currency_conversion( amount = price, source_currency = currency_code, target_currency = @currency, exchange_rate_date = flight_date, on_error = @sql_currency_conversion=>c_on_error-set_to_null ) AS price, * currency_code @currency AS currency_code WHERE carrier_id = @i_carrier_id AND connection_id = @i_connection_id AND flight_date = @i_flight_date INTO CORRESPONDING FIELDS OF @flight_raw.
  8. Accédez à l'implémentation de la méthode GET_FLIGHTS_BY_CARRIER et ajustez-y l'instruction SELECT de la même manière.

    1. Copiez les deux derniers éléments de la liste de zones dans le presse-papiers (price et currency_code).

    2. Passez à l'implémentation de la méthode GET_FLIGHTS_BY_CARRIER.

    3. Dans la liste de zones de l'instruction SELECT, remplacez les deux derniers champs (price et currency_code) par le contenu du presse-papiers.

    4. Adaptez le code comme suit :

      ABAP
      12345678910111213141516
      SELECT FROM /lrn/passflight FIELDS carrier_id, connection_id, flight_date, plane_type_id, seats_max, seats_occupied, seats_max - seats_occupied AS seats_free, currency_conversion( amount = price, source_currency = currency_code, target_currency = @currency, exchange_rate_date = flight_date, on_error = @sql_currency_conversion=>c_on_error-set_to_null ) AS price, @currency AS currency_code WHERE carrier_id = @i_carrier_id INTO TABLE @flights_buffer.
  9. Activez et testez votre classe globale comme application de console.

    1. Appuyez sur Ctrl + F3.

    2. Appuyez sur F9.