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 actualENDLOOP.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 actualENDLOOP.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 necesitasy-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-tabixno está definido (valor 0).sy-subrc: Después deENDLOOP,sy-subrc = 0si se procesó al menos una fila.sy-subrc = 4si ninguna fila cumplió las condiciones (tabla vacía o WHERE sin coincidencias).
Funcionamiento
- La sentencia
LOOP ATcomienza con la primera fila (o la primera fila que coincide conWHERE/FROM). - En cada iteración, la fila actual se proporciona a través del mecanismo de acceso elegido (
INTO,ASSIGNING,REFERENCE INTO). - El bloque de sentencias entre
LOOP ATyENDLOOPse ejecuta una vez para cada fila que coincide. - 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 abiertosENDLOOP.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 10LOOP AT lt_data INTO ls_data FROM 5 TO 10. " ...ENDLOOP.
" Desde fila 100 hasta el finalLOOP 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? | Cambios | Rendimiento | Caso de uso |
|---|---|---|---|---|
INTO | Sí | Requiere MODIFY | Más lento | Solo lectura, sin cambios |
ASSIGNING | No | Directo | Más rápido | Lectura y/o modificación |
REFERENCE INTO | No | Vía ->* | Más rápido | Cuando se necesita referencia |
Recomendación
- Solo lectura sin modificación:
ASSIGNING(más eficiente queINTO) - 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 materialesLOOP 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 > 100LOOP 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 = 0LOOP 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 claveREAD TABLE lt_materials INTO ls_material WITH KEY matnr = 'MAT001'.
" Fila única por índiceREAD 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 filtradosDATA(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 deENDLOOP.CHECK: Termina la iteración actual si la condición es falsa (comoIF 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
-
ASSIGNINGen lugar deINTO: Evita copiar datos y es significativamente más rápido para estructuras grandes. -
Usar condición WHERE: Filtra las filas a procesar y reduce el número de iteraciones.
-
Claves secundarias: Para consultas WHERE frecuentes en ciertos campos, una clave secundaria puede mejorar el rendimiento. Ver también
SORTpara la preparación de búsquedas binarias. -
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.- 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 ATes fundamental para trabajar con tablas internas en ABAP. Cargue datos primero conSELECTdesde la base de datos.- Prefiera
ASSIGNINGpara mejor rendimiento y acceso directo de escritura. - Use condiciones
WHEREpara procesar solo filas relevantes. - No olvide el
ENDLOOPde cierre. - Verifique
sy-subrcdespués del loop si necesita saber si se procesaron filas. - Para tablas hash,
sy-tabixno está disponible – use contadores propios si es necesario. - Para desarrollo ABAP moderno (desde 7.40), verifique si expresiones
FORoREDUCEson más adecuadas para su caso de uso.