La expresion FOR permite iteracion inline dentro de expresiones constructoras como VALUE, REDUCE y NEW. Reemplaza muchas construcciones LOOP AT ... APPEND con sintaxis compacta y funcional.
Sintaxis
1. FOR … IN (Iteracion de tabla)
FOR <variable> IN <tabla> [ INDEX INTO <indice> ] [ WHERE ( <condicion> ) ]2. FOR … UNTIL/WHILE (Iteracion condicional)
FOR <variable> = <valor_inicial> [ THEN <expresion> ] UNTIL <condicion>FOR <variable> = <valor_inicial> [ THEN <expresion> ] WHILE <condicion>3. FOR GROUPS (Agrupacion)
FOR GROUPS <grupo> OF <variable> IN <tabla> GROUP BY <expresion_agrupacion>Principio basico
FOR se usa dentro de VALUE, REDUCE o NEW:
" Crear tabla desde otra tablaDATA(lt_result) = VALUE ty_result_tab( FOR ls_source IN lt_source ( campo1 = ls_source-campo1 campo2 = ls_source-campo2 )).Ejemplos
1. Transformacion simple de tabla
TYPES: BEGIN OF ty_person, id TYPE i, name TYPE string, age TYPE i, END OF ty_person, ty_persons TYPE TABLE OF ty_person WITH EMPTY KEY.
TYPES: ty_names TYPE TABLE OF string WITH EMPTY KEY.
DATA: lt_persons TYPE ty_persons.
lt_persons = VALUE #( ( id = 1 name = 'Juan' age = 30 ) ( id = 2 name = 'Ana' age = 25 ) ( id = 3 name = 'Pedro' age = 35 )).
" Extraer solo nombresDATA(lt_names) = VALUE ty_names( FOR ls_person IN lt_persons ( ls_person-name )).
" Resultado: Juan, Ana, Pedro2. Comparacion: FOR vs LOOP
" === CLASICO CON LOOP ===DATA: lt_names_classic TYPE ty_names.
LOOP AT lt_persons INTO DATA(ls_p). APPEND ls_p-name TO lt_names_classic.ENDLOOP.
" === MODERNO CON FOR ===DATA(lt_names_modern) = VALUE ty_names( FOR ls_p IN lt_persons ( ls_p-name )).3. FOR con WHERE (Filtrar)
" Solo adultos (age >= 18)DATA(lt_adults) = VALUE ty_persons( FOR ls_person IN lt_persons WHERE ( age >= 18 ) ( ls_person )).
" Condicion mas complejaDATA(lt_filtered) = VALUE ty_persons( FOR ls_person IN lt_persons WHERE ( age >= 25 AND name <> 'Juan' ) ( ls_person )).4. Transformacion con calculo
TYPES: BEGIN OF ty_product, id TYPE i, name TYPE string, price TYPE p DECIMALS 2, quantity TYPE i, END OF ty_product.
TYPES: BEGIN OF ty_order_line, product_id TYPE i, total TYPE p DECIMALS 2, END OF ty_order_line, ty_order_lines TYPE TABLE OF ty_order_line WITH EMPTY KEY.
DATA: lt_products TYPE TABLE OF ty_product.
lt_products = VALUE #( ( id = 1 name = 'Widget' price = '10.00' quantity = 5 ) ( id = 2 name = 'Gadget' price = '25.00' quantity = 3 ) ( id = 3 name = 'Gizmo' price = '15.00' quantity = 8 )).
" Calcular lineas de pedido con precio totalDATA(lt_order_lines) = VALUE ty_order_lines( FOR ls_prod IN lt_products ( product_id = ls_prod-id total = ls_prod-price * ls_prod-quantity )).5. INDEX INTO - Leer indice de fila
TYPES: BEGIN OF ty_numbered, position TYPE i, name TYPE string, END OF ty_numbered, ty_numbered_tab TYPE TABLE OF ty_numbered WITH EMPTY KEY.
DATA(lt_numbered) = VALUE ty_numbered_tab( FOR ls_person IN lt_persons INDEX INTO lv_idx ( position = lv_idx name = ls_person-name )).
" Resultado:" position = 1, name = 'Juan'" position = 2, name = 'Ana'" position = 3, name = 'Pedro'6. FOR anidado (Producto cartesiano)
TYPES: ty_colors TYPE TABLE OF string WITH EMPTY KEY, ty_sizes TYPE TABLE OF string WITH EMPTY KEY.
TYPES: BEGIN OF ty_variant, color TYPE string, size TYPE string, END OF ty_variant, ty_variants TYPE TABLE OF ty_variant WITH EMPTY KEY.
DATA: lt_colors TYPE ty_colors, lt_sizes TYPE ty_sizes.
lt_colors = VALUE #( ( `Rojo` ) ( `Azul` ) ( `Verde` ) ).lt_sizes = VALUE #( ( `S` ) ( `M` ) ( `L` ) ).
" Crear todas las combinacionesDATA(lt_variants) = VALUE ty_variants( FOR lv_color IN lt_colors FOR lv_size IN lt_sizes ( color = lv_color size = lv_size )).
" Resultado: 9 combinaciones (3x3)" Rojo-S, Rojo-M, Rojo-L, Azul-S, Azul-M, ...7. FOR … UNTIL (Iteracion condicional)
TYPES: ty_numbers TYPE TABLE OF i WITH EMPTY KEY.
" Generar numeros del 1 al 10DATA(lt_1_to_10) = VALUE ty_numbers( FOR i = 1 UNTIL i > 10 ( i )).
" Con THEN para pasoDATA(lt_even) = VALUE ty_numbers( FOR i = 2 THEN i + 2 UNTIL i > 20 ( i ))." Resultado: 2, 4, 6, 8, 10, 12, 14, 16, 18, 208. FOR … WHILE
" Cuadrados menores que 100DATA(lt_squares) = VALUE ty_numbers( FOR n = 1 WHILE n * n < 100 ( n * n ))." Resultado: 1, 4, 9, 16, 25, 36, 49, 64, 819. FOR GROUPS - Agrupacion
TYPES: BEGIN OF ty_sale, region TYPE string, amount TYPE p DECIMALS 2, END OF ty_sale, ty_sales TYPE TABLE OF ty_sale WITH EMPTY KEY.
DATA: lt_sales TYPE ty_sales.
lt_sales = VALUE #( ( region = 'NORTE' amount = '1000.00' ) ( region = 'SUR' amount = '2000.00' ) ( region = 'NORTE' amount = '1500.00' ) ( region = 'ESTE' amount = '800.00' ) ( region = 'SUR' amount = '1200.00' )).
TYPES: BEGIN OF ty_region_total, region TYPE string, total TYPE p DECIMALS 2, END OF ty_region_total, ty_region_totals TYPE TABLE OF ty_region_total WITH EMPTY KEY.
" Suma por regionDATA(lt_by_region) = VALUE ty_region_totals( FOR GROUPS <group> OF ls_sale IN lt_sales GROUP BY ls_sale-region ( region = <group> total = REDUCE p DECIMALS 2( INIT sum = CONV p DECIMALS 2( 0 ) FOR m IN GROUP <group> NEXT sum = sum + m-amount ) )).
" Resultado:" NORTE: 2500.00" SUR: 3200.00" ESTE: 800.0010. FOR GROUPS con multiples campos de agrupacion
TYPES: BEGIN OF ty_order, year TYPE i, month TYPE i, category TYPE string, amount TYPE p DECIMALS 2, END OF ty_order.
DATA: lt_orders TYPE TABLE OF ty_order.
lt_orders = VALUE #( ( year = 2024 month = 1 category = 'A' amount = 100 ) ( year = 2024 month = 1 category = 'A' amount = 150 ) ( year = 2024 month = 1 category = 'B' amount = 200 ) ( year = 2024 month = 2 category = 'A' amount = 300 )).
TYPES: BEGIN OF ty_group_key, year TYPE i, month TYPE i, END OF ty_group_key.
" Agrupacion por anio y mesDATA(lt_monthly) = VALUE ty_region_totals( FOR GROUPS <grp> OF ls_ord IN lt_orders GROUP BY ( year = ls_ord-year month = ls_ord-month ) ( region = |{ <grp>-year }/{ <grp>-month }| total = REDUCE p DECIMALS 2( INIT s = CONV p DECIMALS 2( 0 ) FOR m IN GROUP <grp> NEXT s = s + m-amount ) )).11. LET para variables locales
TYPES: BEGIN OF ty_display, id TYPE i, display TYPE string, END OF ty_display, ty_displays TYPE TABLE OF ty_display WITH EMPTY KEY.
DATA(lt_display) = VALUE ty_displays( FOR ls_person IN lt_persons LET prefix = 'ID: ' suffix = COND #( WHEN ls_person-age >= 30 THEN ' (Senior)' ELSE '' ) IN ( id = ls_person-id display = |{ prefix }{ ls_person-id } - { ls_person-name }{ suffix }| )).12. FOR en REDUCE
" Suma de todos los importesDATA(lv_total) = REDUCE p DECIMALS 2( INIT sum = CONV p DECIMALS 2( 0 ) FOR ls_sale IN lt_sales NEXT sum = sum + ls_sale-amount).
" Con filtro WHEREDATA(lv_north_total) = REDUCE p DECIMALS 2( INIT sum = CONV p DECIMALS 2( 0 ) FOR ls_sale IN lt_sales WHERE ( region = 'NORTE' ) NEXT sum = sum + ls_sale-amount).13. FOR en NEW (Referencias de datos)
" Crear tabla como referenciaDATA(lr_names) = NEW ty_names( FOR ls_person IN lt_persons ( ls_person-name )).
LOOP AT lr_names->* INTO DATA(lv_name). WRITE: / lv_name.ENDLOOP.14. Extender existente (BASE)
DATA: lt_existing TYPE ty_names.
lt_existing = VALUE #( ( `Existente1` ) ( `Existente2` ) ).
" Agregar nuevas entradasDATA(lt_combined) = VALUE ty_names( BASE lt_existing FOR ls_person IN lt_persons ( ls_person-name )).
" Resultado: Existente1, Existente2, Juan, Ana, Pedro15. Transformacion compleja con CORRESPONDING
TYPES: BEGIN OF ty_source, kunnr TYPE string, name1 TYPE string, ort01 TYPE string, END OF ty_source,
BEGIN OF ty_target, customer_id TYPE string, customer_name TYPE string, city TYPE string, END OF ty_target, ty_targets TYPE TABLE OF ty_target WITH EMPTY KEY.
DATA: lt_source TYPE TABLE OF ty_source.
lt_source = VALUE #( ( kunnr = '1000' name1 = 'Garcia SA' ort01 = 'Madrid' ) ( kunnr = '2000' name1 = 'Lopez SL' ort01 = 'Barcelona' )).
" Transformacion con CORRESPONDINGDATA(lt_target) = VALUE ty_targets( FOR ls_src IN lt_source ( CORRESPONDING #( ls_src MAPPING customer_id = kunnr customer_name = name1 city = ort01 ) )).Variantes FOR en resumen
| Variante | Uso |
|---|---|
FOR var IN itab | Iteracion sobre tabla interna |
FOR var IN itab WHERE (...) | Iteracion filtrada |
FOR var IN itab INDEX INTO idx | Con indice de fila |
FOR i = 1 UNTIL i > n | Iteracion con contador (ascendente) |
FOR i = n THEN i - 1 UNTIL i < 1 | Iteracion con contador (descendente) |
FOR i = 1 WHILE cond | Iteracion condicional |
FOR GROUPS grp OF var IN itab GROUP BY ... | Agrupacion |
Combinaciones
" FOR en VALUEDATA(lt_result) = VALUE ty_tab( FOR ... ( ... ) ).
" FOR en REDUCEDATA(lv_result) = REDUCE type( INIT ... FOR ... NEXT ... ).
" FOR en NEWDATA(lr_result) = NEW ty_tab( FOR ... ( ... ) ).
" FOR anidadoDATA(lt_matrix) = VALUE ty_tab( FOR i = 1 UNTIL i > 3 FOR j = 1 UNTIL j > 3 ( row = i col = j )).Notas importantes / Mejores practicas
FORsolo se puede usar dentro deVALUE,REDUCE,NEW- no de forma independiente.- WHERE filtra de forma mas eficiente que un
IFposterior en el cuerpo. - INDEX INTO proporciona el indice de fila actual (basado en 1).
- FOR anidado crea productos cartesianos - cuidado con tablas grandes!
FOR GROUPSes potente para agregaciones por campos de agrupacion.LETpermite variables auxiliares locales dentro de la expresion FOR.BASEconserva entradas de tabla existentes al construir.- Combinar con
CORRESPONDINGpara transformaciones de estructura. FOR ... UNTIL/WHILEpara iteraciones sin tabla fuente (series numericas, etc.).- Con logica compleja un
LOOP ATpuede ser mas legible.