ABAP AMDP : Procédures de base de données pour SAP HANA

Catégorie
ABAP-Statements
Publié
Auteur
Johannes

AMDP (ABAP Managed Database Procedures) permet l’implémentation de procédures SQLScript directement dans les classes ABAP. Le code est exécuté sur la base de données SAP HANA et offre des performances optimales pour les opérations gourmandes en données.

Prérequis

  • SAP HANA comme base de données
  • ABAP 7.40 SP05 ou supérieur
  • La classe doit implémenter l’interface IF_AMDP_MARKER_HDB

Structure de base

CLASS zcl_amdp_example DEFINITION PUBLIC.
PUBLIC SECTION.
INTERFACES: if_amdp_marker_hdb.
TYPES: BEGIN OF ty_result,
field1 TYPE string,
field2 TYPE i,
END OF ty_result,
ty_results TYPE STANDARD TABLE OF ty_result WITH EMPTY KEY.
CLASS-METHODS: get_data
IMPORTING VALUE(iv_param) TYPE string
EXPORTING VALUE(et_result) TYPE ty_results.
ENDCLASS.
CLASS zcl_amdp_example IMPLEMENTATION.
METHOD get_data BY DATABASE PROCEDURE
FOR HDB
LANGUAGE SQLSCRIPT
OPTIONS READ-ONLY
USING ztable.
et_result = SELECT field1, field2
FROM ztable
WHERE field1 = :iv_param;
ENDMETHOD.
ENDCLASS.

Exemples

1. Procédure AMDP simple

CLASS zcl_customer_amdp DEFINITION PUBLIC.
PUBLIC SECTION.
INTERFACES: if_amdp_marker_hdb.
TYPES: BEGIN OF ty_customer,
kunnr TYPE kunnr,
name1 TYPE name1_gp,
ort01 TYPE ort01_gp,
land1 TYPE land1_gp,
END OF ty_customer,
ty_customers TYPE STANDARD TABLE OF ty_customer WITH EMPTY KEY.
CLASS-METHODS: get_customers_by_country
IMPORTING VALUE(iv_country) TYPE land1_gp
EXPORTING VALUE(et_customers) TYPE ty_customers.
ENDCLASS.
CLASS zcl_customer_amdp IMPLEMENTATION.
METHOD get_customers_by_country BY DATABASE PROCEDURE
FOR HDB
LANGUAGE SQLSCRIPT
OPTIONS READ-ONLY
USING kna1.
et_customers = SELECT kunnr, name1, ort01, land1
FROM kna1
WHERE land1 = :iv_country;
ENDMETHOD.
ENDCLASS.
" Appel
DATA: lt_customers TYPE zcl_customer_amdp=>ty_customers.
zcl_customer_amdp=>get_customers_by_country(
EXPORTING iv_country = 'DE"
IMPORTING et_customers = lt_customers
).
LOOP AT lt_customers INTO DATA(ls_cust).
WRITE: / ls_cust-kunnr, ls_cust-name1, ls_cust-ort01.
ENDLOOP.

2. AMDP avec plusieurs tables

CLASS zcl_order_amdp DEFINITION PUBLIC.
PUBLIC SECTION.
INTERFACES: if_amdp_marker_hdb.
TYPES: BEGIN OF ty_order_detail,
vbeln TYPE vbeln_va,
posnr TYPE posnr_va,
matnr TYPE matnr,
kwmeng TYPE kwmeng,
netwr TYPE netwr,
kunnr TYPE kunnr,
name1 TYPE name1_gp,
END OF ty_order_detail,
ty_order_details TYPE STANDARD TABLE OF ty_order_detail WITH EMPTY KEY.
CLASS-METHODS: get_order_details
IMPORTING VALUE(iv_vbeln) TYPE vbeln_va
EXPORTING VALUE(et_details) TYPE ty_order_details.
ENDCLASS.
CLASS zcl_order_amdp IMPLEMENTATION.
METHOD get_order_details BY DATABASE PROCEDURE
FOR HDB
LANGUAGE SQLSCRIPT
OPTIONS READ-ONLY
USING vbak vbap kna1.
et_details = SELECT p.vbeln,
p.posnr,
p.matnr,
p.kwmeng,
p.netwr,
h.kunnr,
c.name1
FROM vbap AS p
INNER JOIN vbak AS h ON p.vbeln = h.vbeln
INNER JOIN kna1 AS c ON h.kunnr = c.kunnr
WHERE p.vbeln = :iv_vbeln;
ENDMETHOD.
ENDCLASS.

3. AMDP avec variables et logique

CLASS zcl_sales_amdp DEFINITION PUBLIC.
PUBLIC SECTION.
INTERFACES: if_amdp_marker_hdb.
TYPES: BEGIN OF ty_sales_summary,
kunnr TYPE kunnr,
name1 TYPE name1_gp,
order_count TYPE i,
total_value TYPE netwr,
END OF ty_sales_summary,
ty_sales_summaries TYPE STANDARD TABLE OF ty_sales_summary WITH EMPTY KEY.
CLASS-METHODS: get_sales_summary
IMPORTING VALUE(iv_year) TYPE gjahr
EXPORTING VALUE(et_summary) TYPE ty_sales_summaries.
ENDCLASS.
CLASS zcl_sales_amdp IMPLEMENTATION.
METHOD get_sales_summary BY DATABASE PROCEDURE
FOR HDB
LANGUAGE SQLSCRIPT
OPTIONS READ-ONLY
USING vbak kna1.
-- Variable locale pour la plage de dates
DECLARE lv_from_date DATE;
DECLARE lv_to_date DATE;
lv_from_date = CONCAT(:iv_year, '0101');
lv_to_date = CONCAT(:iv_year, '1231');
-- Requête agrégée
et_summary = SELECT k.kunnr,
k.name1,
COUNT(*) AS order_count,
SUM(v.netwr) AS total_value
FROM vbak AS v
INNER JOIN kna1 AS k ON v.kunnr = k.kunnr
WHERE v.erdat BETWEEN :lv_from_date AND :lv_to_date
GROUP BY k.kunnr, k.name1
ORDER BY total_value DESC;
ENDMETHOD.
ENDCLASS.

4. AMDP avec logique IF/CASE

METHOD calculate_discount BY DATABASE PROCEDURE
FOR HDB
LANGUAGE SQLSCRIPT
OPTIONS READ-ONLY
USING zcustomers.
et_result = SELECT kunnr,
name1,
total_sales,
CASE
WHEN total_sales >= 100000 THEN 15
WHEN total_sales >= 50000 THEN 10
WHEN total_sales >= 10000 THEN 5
ELSE 0
END AS discount_percent
FROM zcustomers;
ENDMETHOD.

5. AMDP avec boucles

METHOD process_data BY DATABASE PROCEDURE
FOR HDB
LANGUAGE SQLSCRIPT
OPTIONS READ-ONLY
USING ztable.
DECLARE lv_counter INTEGER;
DECLARE lv_max INTEGER;
-- Charger les données
lt_data = SELECT * FROM ztable;
-- Initialiser le compteur
lv_counter = 1;
SELECT COUNT(*) INTO lv_max FROM :lt_data;
-- Boucle
WHILE lv_counter <= lv_max DO
-- Traitement
lv_counter = lv_counter + 1;
END WHILE;
et_result = SELECT * FROM :lt_data;
ENDMETHOD.

6. AMDP avec tables temporaires

METHOD complex_calculation BY DATABASE PROCEDURE
FOR HDB
LANGUAGE SQLSCRIPT
OPTIONS READ-ONLY
USING vbak vbap.
-- Première table temporaire
lt_headers = SELECT vbeln, kunnr, erdat, netwr
FROM vbak
WHERE erdat >= ADD_DAYS(CURRENT_DATE, -365);
-- Deuxième table temporaire basée sur la première
lt_items = SELECT p.*
FROM vbap AS p
INNER JOIN :lt_headers AS h ON p.vbeln = h.vbeln;
-- Agrégation
lt_summary = SELECT h.kunnr,
COUNT(DISTINCT h.vbeln) AS order_count,
SUM(i.netwr) AS item_total
FROM :lt_headers AS h
INNER JOIN :lt_items AS i ON h.vbeln = i.vbeln
GROUP BY h.kunnr;
-- Résultat
et_result = SELECT * FROM :lt_summary;
ENDMETHOD.

7. Fonction de table CDS

" Définition de vue CDS
@EndUserText.label: 'Sales by Customer (Table Function)"
define table function ZTF_SALES_BY_CUSTOMER
with parameters
@Environment.systemField: #SYSTEM_DATE
p_date : abap.dats
returns {
key kunnr : abap.char(10);
name1 : abap.char(35);
total : abap.dec(15,2);
}
implemented by method zcl_tf_sales=>get_sales;
" Implémentation ABAP
CLASS zcl_tf_sales DEFINITION PUBLIC.
PUBLIC SECTION.
INTERFACES: if_amdp_marker_hdb.
CLASS-METHODS: get_sales
FOR TABLE FUNCTION ztf_sales_by_customer.
ENDCLASS.
CLASS zcl_tf_sales IMPLEMENTATION.
METHOD get_sales BY DATABASE FUNCTION
FOR HDB
LANGUAGE SQLSCRIPT
OPTIONS READ-ONLY
USING vbak kna1.
RETURN SELECT k.kunnr,
k.name1,
SUM(v.netwr) AS total
FROM vbak AS v
INNER JOIN kna1 AS k ON v.kunnr = k.kunnr
WHERE v.erdat <= :p_date
GROUP BY k.kunnr, k.name1;
ENDMETHOD.
ENDCLASS.
" Utilisation en ABAP
SELECT * FROM ztf_sales_by_customer( p_date = @sy-datum )
INTO TABLE @DATA(lt_sales).

8. AMDP avec gestion des erreurs

METHOD process_with_error BY DATABASE PROCEDURE
FOR HDB
LANGUAGE SQLSCRIPT
OPTIONS READ-ONLY
USING ztable.
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
-- Gestion des erreurs
et_errors = SELECT ::SQL_ERROR_CODE AS error_code,
::SQL_ERROR_MESSAGE AS error_message
FROM DUMMY;
END;
-- Traitement normal
et_result = SELECT * FROM ztable;
ENDMETHOD.

9. AMDP avec USING d’un autre AMDP

CLASS zcl_amdp_chain DEFINITION PUBLIC.
PUBLIC SECTION.
INTERFACES: if_amdp_marker_hdb.
CLASS-METHODS: helper_method
IMPORTING VALUE(iv_input) TYPE string
EXPORTING VALUE(et_result) TYPE ty_results.
CLASS-METHODS: main_method
EXPORTING VALUE(et_final) TYPE ty_finals.
ENDCLASS.
CLASS zcl_amdp_chain IMPLEMENTATION.
METHOD helper_method BY DATABASE PROCEDURE
FOR HDB
LANGUAGE SQLSCRIPT
OPTIONS READ-ONLY
USING ztable.
et_result = SELECT * FROM ztable WHERE field = :iv_input;
ENDMETHOD.
METHOD main_method BY DATABASE PROCEDURE
FOR HDB
LANGUAGE SQLSCRIPT
OPTIONS READ-ONLY
USING zcl_amdp_chain=>helper_method.
-- Appeler un autre AMDP
CALL "ZCL_AMDP_CHAIN=>HELPER_METHOD"(
iv_input => 'VALUE',
et_result => lt_temp
);
et_final = SELECT * FROM :lt_temp;
ENDMETHOD.
ENDCLASS.

10. Performance : AMDP vs. Open SQL

" === Open SQL (Standard) ===
" Les données sont transférées du serveur DB au serveur App
SELECT * FROM vbak INTO TABLE @DATA(lt_orders).
LOOP AT lt_orders INTO DATA(ls_order).
" Traitement sur le serveur App
IF ls_order-netwr > 10000.
" ...
ENDIF.
ENDLOOP.
" === AMDP (optimisé) ===
" Traitement directement sur la base de données
zcl_order_amdp=>get_high_value_orders(
EXPORTING iv_min_value = 10000
IMPORTING et_orders = lt_high_value_orders
).
" Seules les données pertinentes sont transférées

11. AMDP avec fonctions de fenêtrage

METHOD get_ranked_sales BY DATABASE PROCEDURE
FOR HDB
LANGUAGE SQLSCRIPT
OPTIONS READ-ONLY
USING vbak.
et_result = SELECT kunnr,
vbeln,
netwr,
ROW_NUMBER() OVER (
PARTITION BY kunnr
ORDER BY netwr DESC
) AS rank_per_customer,
SUM(netwr) OVER (
PARTITION BY kunnr
) AS total_per_customer
FROM vbak;
ENDMETHOD.

12. Exemple pratique : Résolution de hiérarchie

METHOD resolve_hierarchy BY DATABASE PROCEDURE
FOR HDB
LANGUAGE SQLSCRIPT
OPTIONS READ-ONLY
USING zorg_units.
-- Résolution de hiérarchie récursive avec HANA
et_hierarchy = SELECT node_id,
parent_id,
name,
HIERARCHY_LEVEL AS level
FROM HIERARCHY (
SOURCE ( SELECT * FROM zorg_units )
START WHERE parent_id IS NULL
NO ORPHANS
);
ENDMETHOD.

Bases de SQLScript

-- Variables
DECLARE lv_var INTEGER;
DECLARE lv_text NVARCHAR(100);
-- Affectation
lv_var = 42;
lv_text = 'Hello';
-- Variable de table
lt_data = SELECT * FROM table;
-- Condition IF
IF :lv_var > 10 THEN
-- ...
ELSEIF :lv_var > 5 THEN
-- ...
ELSE
-- ...
END IF;
-- Boucle WHILE
WHILE :lv_counter < 100 DO
lv_counter = lv_counter + 1;
END WHILE;
-- Boucle FOR
FOR i IN 1..10 DO
-- ...
END FOR;
-- Curseur
FOR row AS cursor_name DO
-- row.field
END FOR;

Remarques importantes / Bonnes pratiques

  • AMDP uniquement pour SAP HANA – non portable vers d’autres bases de données.
  • READ-ONLY pour les opérations de lecture (par défaut, recommandé).
  • USING déclare tous les objets de base de données et AMDP utilisés.
  • Utilisez Table Functions pour une utilisation dans les vues CDS.
  • Grandes quantités de données à traiter sur la DB plutôt que de les transférer.
  • IF_AMDP_MARKER_HDB doit être implémenté.
  • Testez dans HANA Studio ou SQL Console.
  • Débogage possible via le débogueur HANA (à partir de 7.50).
  • Évitez trop de boucles – pensez en termes d’ensembles.
  • Combinez avec Vues CDS pour un modèle de données optimal.