Sentencia ABAP LOOP AT: Recorrer y procesar tablas internas

Kategorie
ABAP-Statements
Veröffentlicht
Autor
Johannes

La sentencia LOOP AT es una de las estructuras de control más importantes en ABAP para el procesamiento de tablas internas. Permite recorrer todas o algunas filas de una tabla interna secuencialmente y acceder a cada fila individual para leerla, modificarla o eliminarla.

Sintaxis

La sintaxis básica de la sentencia LOOP AT ofrece diferentes variantes para acceder a las filas de la tabla:

1. LOOP con área de trabajo (INTO)

LOOP AT <tabla_interna> INTO <area_trabajo>
[WHERE <condicion>]
[FROM <indice1>] [TO <indice2>].
" Bloque de sentencias
" <area_trabajo> contiene una copia de la fila actual
ENDLOOP.

2. LOOP con field symbol (ASSIGNING)

LOOP AT <tabla_interna> ASSIGNING <field_symbol>
[WHERE <condicion>]
[FROM <indice1>] [TO <indice2>].
" Bloque de sentencias
" <field_symbol> apunta directamente a la fila actual (sin copiar)
ENDLOOP.

3. LOOP con referencia de datos (REFERENCE INTO)

LOOP AT <tabla_interna> REFERENCE INTO <referencia_datos>
[WHERE <condicion>]
[FROM <indice1>] [TO <indice2>].
" Bloque de sentencias
" <referencia_datos> contiene un puntero a la fila actual
ENDLOOP.

4. LOOP sin acceso a fila (solo contar)

LOOP AT <tabla_interna> TRANSPORTING NO FIELDS
[WHERE <condicion>].
" Bloque de sentencias (p. ej. solo usar sy-tabix)
ENDLOOP.

Componentes

  • <tabla_interna>: La tabla cuyas filas se van a recorrer.
  • INTO <area_trabajo>: El contenido de la fila actual se copia al área de trabajo. Los cambios en el área de trabajo no afectan automáticamente a la tabla.
  • ASSIGNING <field_symbol>: El field symbol apunta directamente a la fila actual en la tabla. Los cambios en el field symbol modifican la fila de la tabla inmediatamente.
  • REFERENCE INTO <referencia_datos>: Una referencia de datos que apunta a la fila actual. Acceso mediante dereferenciación (->*).
  • WHERE <condicion>: Filtra las filas a recorrer. Solo se procesan las filas que cumplen la condición.
  • FROM <indice1>: Inicia el loop desde la posición de índice indicada (solo para tablas de índice).
  • TO <indice2>: Termina el loop en la posición de índice indicada (solo para tablas de índice).
  • TRANSPORTING NO FIELDS: No se transportan contenidos de campo. Útil para contar o cuando solo se necesita sy-tabix.

Campos del sistema durante el Loop

Dentro de un LOOP AT se establecen campos del sistema importantes:

  • sy-tabix: Contiene el índice de fila actual de la fila que se está procesando (para tablas estándar y ordenadas). Para tablas hash, sy-tabix no está definido (valor 0).
  • sy-subrc: Después de ENDLOOP, sy-subrc = 0 si se procesó al menos una fila. sy-subrc = 4 si ninguna fila cumplió las condiciones (tabla vacía o WHERE sin coincidencias).

Funcionamiento

  1. La sentencia LOOP AT comienza con la primera fila (o la primera fila que coincide con WHERE/FROM).
  2. En cada iteración, la fila actual se proporciona a través del mecanismo de acceso elegido (INTO, ASSIGNING, REFERENCE INTO).
  3. El bloque de sentencias entre LOOP AT y ENDLOOP se ejecuta una vez para cada fila que coincide.
  4. Después de la última fila (o cuando no hay más filas coincidentes), el loop termina y el programa continúa después de ENDLOOP.

Variantes y adiciones

Condición WHERE

Con WHERE se pueden filtrar las filas para que solo se recorran ciertas filas:

LOOP AT lt_orders INTO ls_order WHERE status = 'OPEN'.
" Solo procesar pedidos abiertos
ENDLOOP.

La condición WHERE soporta:

  • Operadores de comparación: =, <>, <, >, <=, >=
  • Conexiones lógicas: AND, OR, NOT
  • Verificación de rangos: BETWEEN, IN (para Ranges)
  • Pattern-Matching: CP, NP (para cadenas de caracteres)

FROM y TO (basado en índice)

Para tablas estándar y ordenadas se puede restringir el rango:

" Solo procesar filas 5 a 10
LOOP AT lt_data INTO ls_data FROM 5 TO 10.
" ...
ENDLOOP.
" Desde fila 100 hasta el final
LOOP AT lt_data INTO ls_data FROM 100.
" ...
ENDLOOP.

GROUP BY (Agrupación)

Desde ABAP 7.40 las filas pueden agruparse durante el loop:

LOOP AT lt_orders INTO ls_order
GROUP BY ( customer = ls_order-customer_id
size = GROUP SIZE )
INTO DATA(group).
" Procesamiento de grupo
LOOP AT GROUP group INTO DATA(member).
" Miembros individuales del grupo
ENDLOOP.
ENDLOOP.

INTO vs. ASSIGNING vs. REFERENCE INTO

La elección del mecanismo de acceso afecta el rendimiento y la funcionalidad:

Variante¿Copia?CambiosRendimientoCaso de uso
INTORequiere MODIFYMás lentoSolo lectura, sin cambios
ASSIGNINGNoDirectoMás rápidoLectura y/o modificación
REFERENCE INTONoVía ->*Más rápidoCuando se necesita referencia

Recomendación

  • Solo lectura sin modificación: ASSIGNING (más eficiente que INTO)
  • Lectura y modificación: ASSIGNING (cambios aplican inmediatamente)
  • Pasar referencia: REFERENCE INTO
  • Se desea copia explícitamente: INTO

Ejemplos

1. LOOP simple con INTO

TYPES: BEGIN OF ty_material,
matnr TYPE matnr,
maktx TYPE maktx,
menge TYPE i,
END OF ty_material.
DATA: lt_materials TYPE STANDARD TABLE OF ty_material,
ls_material TYPE ty_material.
" Llenar tabla (datos de ejemplo)
lt_materials = VALUE #(
( matnr = 'MAT001' maktx = 'Tornillo M6' menge = 100 )
( matnr = 'MAT002' maktx = 'Tuerca M6' menge = 200 )
( matnr = 'MAT003' maktx = 'Arandela M6' menge = 150 )
).
" Mostrar todos los materiales
LOOP AT lt_materials INTO ls_material.
WRITE: / sy-tabix, ':', ls_material-matnr, ls_material-maktx.
ENDLOOP.

2. LOOP con ASSIGNING y modificación de valor

FIELD-SYMBOLS: <fs_material> TYPE ty_material.
" Aumentar todas las cantidades en 10%
LOOP AT lt_materials ASSIGNING <fs_material>.
<fs_material>-menge = <fs_material>-menge * '1.1'.
ENDLOOP.
" ¡Los cambios aplican inmediatamente en lt_materials!

3. LOOP con condición WHERE

DATA: lv_total TYPE i VALUE 0.
" Solo sumar materiales con cantidad > 100
LOOP AT lt_materials INTO ls_material WHERE menge > 100.
lv_total = lv_total + ls_material-menge.
ENDLOOP.
WRITE: / 'Cantidad total (>100):', lv_total.
IF sy-subrc <> 0.
WRITE: / 'No se encontraron materiales con cantidad > 100.'.
ENDIF.

4. LOOP con REFERENCE INTO

DATA: lr_material TYPE REF TO ty_material.
LOOP AT lt_materials REFERENCE INTO lr_material.
" Acceso mediante dereferenciación
lr_material->menge = lr_material->menge + 50.
ENDLOOP.

5. Eliminar filas en el LOOP

" Eliminar filas con cantidad = 0
LOOP AT lt_materials ASSIGNING <fs_material>.
IF <fs_material>-menge = 0.
DELETE lt_materials.
ENDIF.
ENDLOOP.

Nota: Eliminar filas dentro de un LOOP está permitido. El loop continúa correctamente con la siguiente fila. Ver también DELETE para más variantes.

6. LOOP con FROM/TO para paginación

CONSTANTS: lc_page_size TYPE i VALUE 10.
DATA: lv_page TYPE i VALUE 2,
lv_from TYPE i,
lv_to TYPE i.
lv_from = ( lv_page - 1 ) * lc_page_size + 1.
lv_to = lv_page * lc_page_size.
LOOP AT lt_materials INTO ls_material FROM lv_from TO lv_to.
" Procesar filas 11-20 (página 2)
WRITE: / ls_material-matnr.
ENDLOOP.

7. TRANSPORTING NO FIELDS para contar

DATA: lv_count TYPE i VALUE 0.
LOOP AT lt_materials TRANSPORTING NO FIELDS WHERE menge > 100.
lv_count = lv_count + 1.
ENDLOOP.
WRITE: / 'Cantidad de materiales con cantidad > 100:', lv_count.

Consejo: Para solo contar, la función REDUCE o lines() con FILTER suele ser más elegante:

DATA(lv_count) = REDUCE i( INIT count = 0
FOR wa IN lt_materials WHERE ( menge > 100 )
NEXT count = count + 1 ).

Distinción con otras sentencias

LOOP vs. READ TABLE

  • LOOP AT: Recorre múltiples/todas las filas secuencialmente.
  • READ TABLE: Lee una única fila específica (por clave o índice).

Para acceder a una única fila, READ TABLE es más eficiente:

" Fila única por clave
READ TABLE lt_materials INTO ls_material WITH KEY matnr = 'MAT001'.
" Fila única por índice
READ TABLE lt_materials INTO ls_material INDEX 1.

LOOP vs. expresión FOR

Desde ABAP 7.40 existe la expresión FOR para iteraciones inline:

" Crear nueva tabla con datos filtrados
DATA(lt_filtered) = VALUE ty_materials(
FOR wa IN lt_materials WHERE ( menge > 100 )
( wa )
).

LOOP AT sigue siendo la opción preferida para lógica de procesamiento compleja con múltiples sentencias.

Control del bucle

Dentro de un LOOP AT las siguientes sentencias pueden controlar el bucle:

  • CONTINUE: Salta a la siguiente iteración (omite el resto de la iteración actual).
  • EXIT: Termina el bucle inmediatamente y continúa después de ENDLOOP.
  • CHECK: Termina la iteración actual si la condición es falsa (como IF NOT ... CONTINUE).
LOOP AT lt_materials ASSIGNING <fs_material>.
" Omitir materiales sin texto
CHECK <fs_material>-maktx IS NOT INITIAL.
" Terminar en material especial
IF <fs_material>-matnr = 'STOP'.
EXIT.
ENDIF.
" Procesamiento...
ENDLOOP.

Consejos de rendimiento

  1. ASSIGNING en lugar de INTO: Evita copiar datos y es significativamente más rápido para estructuras grandes.

  2. Usar condición WHERE: Filtra las filas a procesar y reduce el número de iteraciones.

  3. Claves secundarias: Para consultas WHERE frecuentes en ciertos campos, una clave secundaria puede mejorar el rendimiento. Ver también SORT para la preparación de búsquedas binarias.

  4. PARALLEL CURSOR: Al procesar dos tablas ordenadas con relación entre sí, la técnica de cursor paralelo puede mejorar drásticamente el rendimiento:

DATA: lv_tabix TYPE sy-tabix VALUE 1.
LOOP AT lt_header INTO ls_header.
LOOP AT lt_items INTO ls_item FROM lv_tabix.
IF ls_item-header_id <> ls_header-id.
lv_tabix = sy-tabix.
EXIT.
ENDIF.
" Procesar item...
ENDLOOP.
ENDLOOP.
  1. Evitar LOOPs anidados sin índice: Dos loops anidados sobre tablas grandes sin optimización llevan a complejidad O(n^2).

Notas importantes / Mejores prácticas

  • LOOP AT es fundamental para trabajar con tablas internas en ABAP. Cargue datos primero con SELECT desde la base de datos.
  • Prefiera ASSIGNING para mejor rendimiento y acceso directo de escritura.
  • Use condiciones WHERE para procesar solo filas relevantes.
  • No olvide el ENDLOOP de cierre.
  • Verifique sy-subrc después del loop si necesita saber si se procesaron filas.
  • Para tablas hash, sy-tabix no está disponible – use contadores propios si es necesario.
  • Para desarrollo ABAP moderno (desde 7.40), verifique si expresiones FOR o REDUCE son más adecuadas para su caso de uso.