Le Open SQL moderne (à partir de ABAP 7.50+) offre des fonctionnalités puissantes comme Common Table Expressions (WITH), Window Functions et des expressions avancées. Ces fonctionnalités permettent des requêtes complexes directement en ABAP.
Nouvelles fonctionnalités par version
| Fonctionnalité | À partir de |
|---|---|
| Déclaration inline, variables hôtes | 7.40 SP05 |
| Expressions CASE | 7.50 |
| Literaux, calculs | 7.50 |
| Fonctions de chaînes | 7.50 |
| Window Functions | 7.50 |
| WITH (CTE) | 7.51 |
| Cross Join, Outer Apply | 7.52 |
| Fonctions hiérarchiques | 7.53 |
WITH – Common Table Expressions (CTE)
1. CTE simple
WITH +customers AS ( SELECT kunnr, name1, land1 FROM kna1 WHERE land1 = 'DE" )SELECT * FROM +customers INTO TABLE @DATA(lt_german_customers).2. Plusieurs CTEs
WITH +orders AS ( SELECT vbeln, kunnr, netwr, erdat FROM vbak WHERE erdat >= '20240101" ), +customers AS ( SELECT kunnr, name1 FROM kna1 )SELECT o~vbeln, o~netwr, c~name1 FROM +orders AS o INNER JOIN +customers AS c ON o~kunnr = c~kunnr INTO TABLE @DATA(lt_orders_with_names).3. CTE avec agrégation
WITH +order_totals AS ( SELECT kunnr, COUNT(*) AS order_count, SUM( netwr ) AS total_value FROM vbak GROUP BY kunnr )SELECT c~kunnr, c~name1, t~order_count, t~total_value FROM kna1 AS c INNER JOIN +order_totals AS t ON c~kunnr = t~kunnr WHERE t~total_value > 100000 INTO TABLE @DATA(lt_top_customers).4. CTE récursive (hiérarchies)
WITH +hierarchy( node, parent, level ) AS ( " Noeud de départ SELECT org_id, parent_id, 1 AS level FROM zorg_structure WHERE parent_id IS INITIAL UNION ALL " Partie récursive SELECT child~org_id, child~parent_id, parent~level + 1 FROM zorg_structure AS child INNER JOIN +hierarchy AS parent ON child~parent_id = parent~node )SELECT * FROM +hierarchy INTO TABLE @DATA(lt_org_tree).Window Functions
5. ROW_NUMBER – Numérotation des lignes
SELECT kunnr, vbeln, netwr, ROW_NUMBER( ) OVER( PARTITION BY kunnr ORDER BY netwr DESC ) AS rank FROM vbak INTO TABLE @DATA(lt_ranked_orders).
" Seulement le top 3 par clientSELECT * FROM @lt_ranked_orders AS t WHERE t~rank <= 3 INTO TABLE @DATA(lt_top3).6. RANK et DENSE_RANK
SELECT matnr, werks, lgort, labst, RANK( ) OVER( PARTITION BY matnr ORDER BY labst DESC ) AS rank, DENSE_RANK( ) OVER( PARTITION BY matnr ORDER BY labst DESC ) AS dense_rank FROM mard INTO TABLE @DATA(lt_stock_ranked).
" RANK: 1, 2, 2, 4 (lacunes pour les valeurs égales)" DENSE_RANK: 1, 2, 2, 3 (pas de lacunes)7. SUM OVER – Somme cumulée
SELECT vbeln, erdat, netwr, SUM( netwr ) OVER( ORDER BY erdat ) AS running_total FROM vbak WHERE kunnr = '0000001000" INTO TABLE @DATA(lt_running_total).8. LAG et LEAD – Ligne précédente/suivante
SELECT vbeln, erdat, netwr, LAG( netwr, 1 ) OVER( ORDER BY erdat ) AS prev_order_value, LEAD( netwr, 1 ) OVER( ORDER BY erdat ) AS next_order_value FROM vbak WHERE kunnr = '0000001000" ORDER BY erdat INTO TABLE @DATA(lt_with_neighbors).
" Calculer le changement par rapport au mois précédentLOOP AT lt_with_neighbors INTO DATA(ls_order). IF ls_order-prev_order_value IS NOT INITIAL. DATA(lv_change) = ls_order-netwr - ls_order-prev_order_value. ENDIF.ENDLOOP.9. FIRST_VALUE et LAST_VALUE
SELECT kunnr, vbeln, erdat, netwr, FIRST_VALUE( netwr ) OVER( PARTITION BY kunnr ORDER BY erdat ) AS first_order_value, LAST_VALUE( netwr ) OVER( PARTITION BY kunnr ORDER BY erdat ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) AS last_order_value FROM vbak INTO TABLE @DATA(lt_first_last).10. AVG/MIN/MAX OVER – Agrégation de fenêtre
SELECT kunnr, vbeln, netwr, AVG( netwr ) OVER( PARTITION BY kunnr ) AS avg_order_value, MIN( netwr ) OVER( PARTITION BY kunnr ) AS min_order_value, MAX( netwr ) OVER( PARTITION BY kunnr ) AS max_order_value FROM vbak INTO TABLE @DATA(lt_with_stats).
" Comparaison avec la moyenneLOOP AT lt_with_stats INTO DATA(ls_order). IF ls_order-netwr > ls_order-avg_order_value. WRITE: / ls_order-vbeln, 'Au-dessus de la moyenne'. ENDIF.ENDLOOP.Expressions CASE
11. CASE WHEN
SELECT vbeln, netwr, CASE WHEN netwr >= 10000 THEN 'HIGH" WHEN netwr >= 1000 THEN 'MEDIUM" ELSE 'LOW" END AS value_category FROM vbak INTO TABLE @DATA(lt_categorized).12. CASE avec champ
SELECT vbeln, auart, CASE auart WHEN 'TA' THEN 'Commande standard" WHEN 'SO' THEN 'Commande urgente" WHEN 'RE' THEN 'Retours" ELSE 'Autre" END AS order_type_text FROM vbak INTO TABLE @DATA(lt_with_text).13. CASE dans l’agrégation
SELECT kunnr, COUNT(*) AS total_orders, SUM( CASE WHEN netwr >= 10000 THEN 1 ELSE 0 END ) AS high_value_count, SUM( CASE WHEN netwr < 1000 THEN 1 ELSE 0 END ) AS low_value_count FROM vbak GROUP BY kunnr INTO TABLE @DATA(lt_order_analysis).Literaux et calculs
14. Literaux dans SELECT
SELECT vbeln, 'EUR' AS currency, 2024 AS year, netwr * 1.19 AS gross_value FROM vbak INTO TABLE @DATA(lt_with_literals).15. Expressions arithmétiques
SELECT matnr, labst, insme, labst - insme AS available_stock, labst + insme AS total_quantity, CASE WHEN labst > 0 THEN insme * 100 / labst ELSE 0 END AS inspection_percentage FROM mard INTO TABLE @DATA(lt_stock_calc).Fonctions de chaînes
16. CONCAT et opérations sur les chaînes
SELECT kunnr, CONCAT( name1, CONCAT( ' (', CONCAT( ort01, ')' ) ) ) AS display_name, LENGTH( name1 ) AS name_length, LEFT( kunnr, 4 ) AS prefix FROM kna1 INTO TABLE @DATA(lt_formatted).17. SUBSTRING et REPLACE
SELECT vbeln, SUBSTRING( vbeln, 1, 4 ) AS prefix, REPLACE( vbeln, '00', 'XX' ) AS replaced FROM vbak INTO TABLE @DATA(lt_string_ops).18. UPPER, LOWER, TRIM
SELECT name1, UPPER( name1 ) AS upper_name, LOWER( name1 ) AS lower_name, LTRIM( name1, ' ' ) AS left_trimmed, RTRIM( name1, ' ' ) AS right_trimmed FROM kna1 INTO TABLE @DATA(lt_case_converted).Fonctions de date
19. Calculs de date
SELECT vbeln, erdat, DATS_DAYS_BETWEEN( erdat, @sy-datum ) AS days_ago, DATS_ADD_DAYS( erdat, 30 ) AS plus_30_days, DATS_ADD_MONTHS( erdat, 1 ) AS plus_1_month FROM vbak INTO TABLE @DATA(lt_with_dates).20. Extraction de date
SELECT vbeln, erdat, EXTRACT( YEAR FROM erdat ) AS year, EXTRACT( MONTH FROM erdat ) AS month, EXTRACT( DAY FROM erdat ) AS day FROM vbak INTO TABLE @DATA(lt_date_parts).
" Regroupement par année/moisSELECT EXTRACT( YEAR FROM erdat ) AS year, EXTRACT( MONTH FROM erdat ) AS month, COUNT(*) AS order_count, SUM( netwr ) AS total_value FROM vbak GROUP BY EXTRACT( YEAR FROM erdat ), EXTRACT( MONTH FROM erdat ) INTO TABLE @DATA(lt_monthly).Conversion de type
21. CAST
SELECT vbeln, CAST( netwr AS CHAR( 20 ) ) AS netwr_string, CAST( '12345' AS INT4 ) AS number_value, CAST( erdat AS CHAR( 8 ) ) AS date_string FROM vbak INTO TABLE @DATA(lt_casted).22. COALESCE (gestion des NULL)
SELECT kunnr, name1, COALESCE( name2, '' ) AS name2_safe, COALESCE( ort01, 'Inconnu' ) AS city FROM kna1 INTO TABLE @DATA(lt_with_defaults).JOINs avancés
23. Cross Join
SELECT c~kunnr, y~year FROM kna1 AS c CROSS JOIN ( SELECT DISTINCT EXTRACT( YEAR FROM erdat ) AS year FROM vbak ) AS y INTO TABLE @DATA(lt_customer_years).24. Outer Apply (sous-requête corrélée)
SELECT c~kunnr, c~name1, o~last_order, o~last_value FROM kna1 AS c LEFT OUTER JOIN ( SELECT kunnr, MAX( erdat ) AS last_order, MAX( netwr ) AS last_value FROM vbak GROUP BY kunnr ) AS o ON c~kunnr = o~kunnr INTO TABLE @DATA(lt_with_last_order).Sous-requêtes
25. Sous-requête scalaire
SELECT vbeln, kunnr, netwr, ( SELECT name1 FROM kna1 WHERE kunnr = vbak~kunnr ) AS customer_name FROM vbak INTO TABLE @DATA(lt_with_name).26. EXISTS
SELECT kunnr, name1 FROM kna1 AS c WHERE EXISTS ( SELECT * FROM vbak WHERE kunnr = c~kunnr AND erdat >= '20240101" ) INTO TABLE @DATA(lt_active_customers).27. IN avec sous-requête
SELECT * FROM kna1 WHERE kunnr IN ( SELECT DISTINCT kunnr FROM vbak WHERE netwr > 50000 ) INTO TABLE @DATA(lt_high_value_customers).Conseils de performance
" 1. CTE au lieu de plusieurs sous-requêtes identiquesWITH +high_value AS ( SELECT kunnr FROM vbak WHERE netwr > 50000 )SELECT * FROM kna1 WHERE kunnr IN ( SELECT kunnr FROM +high_value ) INTO TABLE @lt_result.
" 2. Window Functions au lieu de sous-requêtes corrélées" LENT :SELECT vbeln, netwr, ( SELECT SUM( netwr ) FROM vbak AS inner WHERE inner~kunnr = outer~kunnr ) FROM vbak AS outer INTO TABLE @lt_slow.
" RAPIDE :SELECT vbeln, netwr, SUM( netwr ) OVER( PARTITION BY kunnr ) AS customer_total FROM vbak INTO TABLE @lt_fast.
" 3. Filtrer tôt avec WHEREWITH +filtered AS ( SELECT * FROM vbak WHERE erdat >= '20240101' " Filtrer ici )SELECT * FROM +filtered ...Remarques importantes / Bonnes pratiques
- WITH (CTE) pour des sous-requêtes lisibles et réutilisables.
- Window Functions pour le classement, les sommes cumulées et les comparaisons.
- CASE pour des valeurs conditionnelles directement dans SELECT.
- Literaux pour des valeurs constantes dans le résultat.
- COALESCE pour des requêtes sûres avec NULL.
- Utilisez les fonctions de date au lieu d’opérations sur les chaînes pour les dates.
- ROW_NUMBER() OVER() pour la pagination et les requêtes Top-N.
- Les CTEs peuvent être récursives pour les hiérarchies.
- Vérifiez la version ABAP pour la disponibilité des fonctionnalités.
- Combinez avec CDS Views pour des définitions réutilisables.