El Open SQL moderno (desde ABAP 7.50+) ofrece características potentes como Common Table Expressions (WITH), Window Functions y expresiones avanzadas. Estas funciones permiten consultas complejas directamente en ABAP.
Nuevas características por versión
| Característica | Desde versión |
|---|---|
| Declaración inline, variables host | 7.40 SP05 |
| Expresiones CASE | 7.50 |
| Literales, cálculos | 7.50 |
| Funciones de cadena | 7.50 |
| Window Functions | 7.50 |
| WITH (CTE) | 7.51 |
| Cross Join, Outer Apply | 7.52 |
| Funciones de jerarquía | 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. Múltiples 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 con agregación
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 recursiva (jerarquías)
WITH +hierarchy( node, parent, level ) AS ( " Nodos iniciales SELECT org_id, parent_id, 1 AS level FROM zorg_structure WHERE parent_id IS INITIAL UNION ALL " Parte recursiva 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 - Numeración de filas
SELECT kunnr, vbeln, netwr, ROW_NUMBER( ) OVER( PARTITION BY kunnr ORDER BY netwr DESC ) AS rank FROM vbak INTO TABLE @DATA(lt_ranked_orders).
" Solo Top-3 por clienteSELECT * FROM @lt_ranked_orders AS t WHERE t~rank <= 3 INTO TABLE @DATA(lt_top3).6. RANK y 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 (huecos en valores iguales)" DENSE_RANK: 1, 2, 2, 3 (sin huecos)7. SUM OVER - Suma acumulativa
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 y LEAD - Fila anterior/siguiente
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).
" Calcular cambio respecto al mes anteriorLOOP 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 y 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 - Agregación de ventana
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).
" Comparación con promedioLOOP AT lt_with_stats INTO DATA(ls_order). IF ls_order-netwr > ls_order-avg_order_value. WRITE: / ls_order-vbeln, 'Por encima del promedio'. ENDIF.ENDLOOP.Expresiones CASE
11. CASE WHEN
SELECT vbeln, netwr, CASE WHEN netwr >= 10000 THEN 'ALTO' WHEN netwr >= 1000 THEN 'MEDIO' ELSE 'BAJO' END AS value_category FROM vbak INTO TABLE @DATA(lt_categorized).12. CASE con campo
SELECT vbeln, auart, CASE auart WHEN 'TA' THEN 'Pedido estándar' WHEN 'SO' THEN 'Pedido urgente' WHEN 'RE' THEN 'Devolución' ELSE 'Otro' END AS order_type_text FROM vbak INTO TABLE @DATA(lt_with_text).13. CASE en agregación
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).Literales y cálculos
14. Literales en SELECT
SELECT vbeln, 'EUR' AS currency, 2024 AS year, netwr * 1.19 AS gross_value FROM vbak INTO TABLE @DATA(lt_with_literals).15. Expresiones aritméticas
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).Funciones de cadena
16. CONCAT y operaciones de cadena
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 y 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).Funciones de fecha
19. Cálculos de fecha
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. Extracción de fecha
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).
" Agrupación por año/mesSELECT 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).Conversión de tipos
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 (tratamiento de NULL)
SELECT kunnr, name1, COALESCE( name2, '' ) AS name2_safe, COALESCE( ort01, 'Desconocido' ) AS city FROM kna1 INTO TABLE @DATA(lt_with_defaults).JOINs extendidos
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 (Subconsulta correlacionada)
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).Subconsultas
25. Subconsulta escalar
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 con subconsulta
SELECT * FROM kna1 WHERE kunnr IN ( SELECT DISTINCT kunnr FROM vbak WHERE netwr > 50000 ) INTO TABLE @DATA(lt_high_value_customers).Consejos de rendimiento
" 1. CTE en lugar de múltiples subconsultas igualesWITH +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 en lugar de subconsultas correlacionadas" LENTO:SELECT vbeln, netwr, ( SELECT SUM( netwr ) FROM vbak AS inner WHERE inner~kunnr = outer~kunnr ) FROM vbak AS outer INTO TABLE @lt_slow.
" RÁPIDO:SELECT vbeln, netwr, SUM( netwr ) OVER( PARTITION BY kunnr ) AS customer_total FROM vbak INTO TABLE @lt_fast.
" 3. Filtrar temprano con WHEREWITH +filtered AS ( SELECT * FROM vbak WHERE erdat >= '20240101' " Filtro aquí )SELECT * FROM +filtered ...Notas importantes / Mejores prácticas
- WITH (CTE) para subconsultas legibles y reutilizables.
- Window Functions para ranking, sumas acumulativas y comparaciones.
- CASE para valores condicionales directamente en SELECT.
- Literales para valores constantes en el resultado.
- COALESCE para consultas seguras ante NULL.
- Usa funciones de fecha en lugar de operaciones de cadena sobre fechas.
- ROW_NUMBER() OVER() para paginación y consultas Top-N.
- Las CTEs pueden ser recursivas para jerarquías.
- Verifica la versión de ABAP para disponibilidad de características.
- Combina con CDS Views para definiciones reutilizables.