Buen día a todos, gracias a
los usuarios que me han dejado comentarios ya que son de gran ayuda. En esta
oportunidad quiero hablarles sobre los bucles que podemos utilizar en el
lenguaje ABAP, ya que a veces se nos presentan problemas de rendimiento y no
sabemos el porqué.
Bucles
en SAP ABAP
En un bucle, un bloque de
instrucciones se ejecuta varias veces en la serie. Existen cuatro tipos de bucles en ABAP:
- Los bucles sentencia DO (principalmente para los bucles incondicionales)
- Los bucles WHILE (principalmente para los bucles condicionales)
- Los bucles instrucción SELECT (bucle a través de los datos de base de datos)
- Los bucles sentencia LOOP (bucle en las tablas internas)
Bucle
DO - ENDDO “Bucle incondicional”
Ejecución de sentencias
indefinidamente hasta que se procese la sentencia EXIT, STOP o REJECT.
Sintaxis:
DO [ TIMES ] [ VARYING FROM NEXT ]
ENDDO.
La sentencia DO sin cláusulas ejecuta el bloque de sentencias indefinidamente, o hasta que se procese una sentencia EXIT, STOP o REJECT. Para limitar el número de pasos de un bucle se puede utilizar la opción TIMES. Puede ser un literal o una variable. Si es 0 o negativo, el sistema no procesará el bucle.
La cláusula ENDDO es obligatoria (marca el fin del
bloque de sentencias). La variable SY-INDEX
contiene el número de veces que el bucle ha sido ejecutado.
Utilizando la opción VARYING se pueden ir asignando valores
a una variable a partir de un conjunto de campos del mismo tipo y longitud de
memoria por cada paso de bucle. En una sentencia DO se pueden utilizar varias
opciones VARYING.
Ejemplo:
DO.
WRITE: / SY-INDEX – Inicio:’, (3)
SY-INDEX.
IF SY-INDEX = 10.
EXIT.
ENDIF.
WRITE: ‘Fin:’, (3) SY-INDEX.
ENDDO.
Otro ejemplo simple de un bucle DO:
DO.
WRITE sy-index.
IF sy-index = 3.
EXIT.
ENDIF.
ENDDO.
La salida de la lista es la siguiente: 1, 2, 3.
El bucle se procesa tres
veces. Aquí, el procesamiento pasa a través del bucle de tres veces y luego sale
ejecutando la instrucción EXIT.
Ejemplo
de dos bucles anidados con la adición TIEMPOS:
DO 2 TIMES.
WRITE sy-index.
SKIP. “salta 1 línea.
DO 3 TIMES.
WRITE sy-index.
ENDDO.
SKIP.
ENDDO.
La salida de la lista es la
siguiente: Primer DO 1, Segundo DO 1 2 3, Primer DO 2, Segundo DO 1
2 3.
El bucle exterior se procesa
dos veces. Cada vez que se procesa el bucle exterior, el bucle interno se
procesa en tres ocasiones. Debemos tener en cuenta que el campo del sistema sy-index
contiene el número de bucle que pasa por cada bucle individual.
Bucle
WHILE – ENDWHILE “Bucles condicional”
Se utiliza para repetir un
bloque de instrucciones durante el tiempo que una determinada condición es
verdadera, utilice la siguiente estructura de control:
Sintaxis:
WHILE log_exp o [ VARY FROM NEXT ].
[statemaent_block]
ENDWHILE.
log_exp
puede ser cualquier expresión lógica. El bloque de instrucciones entre WHILE y ENDWHILE se repite mientras la condición es verdadera o hasta que
una declaración de terminación, tales como cierre o detenga ocurre. El campo
del sistema sy-index contiene el número de bucle pasa.
El sistema procesa el bloque
de sentencias hasta que se cumpla la condición o hasta que el sistema procesa
una sentencia EXIT, STOP o REJECT. Para condición se puede utilizar cualquier expresión
lógica. El campo del sistema SY-INDEX contiene el número de veces que el bucle
ha sido ejecutado. El sistema permite anidar sentencias WHILE, así como
combinarlas con otras sentencias de bucle.
La opción VARY actúa de la misma forma en que
actúa la opción VARYING en la
sentencia DO. Al igual en la sentencia DO, se puede utilizar más de una opción
VARY en una sentencia WHILE.
Ejemplo:
DATA: SEARCH_ME TYPE I,
MIN TYPE I
VALUE 0,
MAX TYPE I
VALUE 1000,
TRIES TYPE I,
NUMBER TYPE I.
SEARCH_ME =
23.
WHILE NUMBER
SEARCH_ME.
ADD 1 TO
TRIES.
NUMBER = ( MIN
+ MAX ) / 2.
IF NUMBER >
SEARCH_ME.
MAX = NUMBER – 1.
ELSE.
MIN = NUMBER + 1.
ENDIF.
ENDWHILE.
ENDWHILE.
Para
la utilización y explicación de los Bucles Select y Loop, utilizaremos Tablas
internas, por ello les hablare un poco sobre ellas:
Las tablas internas sirven
para almacenar información extraída de la base de datos. En este ejemplo voy a
declarar una tabla interna de la siguiente forma:
* Tabla de vuelos
DATA:
BEGIN OF i_vuelos OCCURS 0,
carrid LIKE sflight-carrid, "Código de
aerolínea
connid LIKE sflight-connid, "Número de
vuelo
fldate LIKE sflight-fldate, "Fecha de
vuelo
planetype LIKE sflight-planetype, "Tipo de avión
END OF i_vuelos.
Bucle
SELECT - ENDSELECT “Bucle a través de los datos de base de datos”
Esta sentencia realiza una
lectura lineal de los datos de las tablas de la base de datos y los asigna
directamente a los campos de nuestra tabla interna. Pero atención, para que
queden almacenados sobre la tabla interna para cada registro seleccionado
debemos utilizar la sentencia APPEND. Así, haremos añadiremos los registros a
nuestra tabla interna.
SELECT * FROM sflight WHERE carrid IN s_carrid.
i_vuelos-carrid
= sflight-carrid.
i_vuelos-connid = sflight-connid.
i_vuelos-fldate = sflight-fldate.
i_vuelos-planetype = sflight-planetype.
APPEND i_vuelos. CLEAR i_vuelos.
ENDSELECT.
El símbolo (*) le indica a
SAP que debe guardar en memoria absolutamente todos los valores de todos los
campos de cada registro de la tabla SAP.
La cláusula WHERE nos
permite indicar el filtro de selección. En este caso utilizamos como filtro el
rango de códigos de aerolíneas. De la tabla sflight sólo recuperaremos aquellos
registros que cumplan con la condición indicada en el WHERE.
Seguidamente asignamos a
cada campo de la tabla interna el valor del campo de la tabla SAP, dejándolo a
nivel de la cabecera de la tabla interna.
Finalmente, guardamos el
registro en nuestra tabla interna mediante la sentencia APPEND.
Con la sentencia CLEAR limpiamos la cabecera y la dejamos lista para el siguiente registro.
Con la sentencia CLEAR limpiamos la cabecera y la dejamos lista para el siguiente registro.
La sentencia SELECT...ENDSELECT irá pasando uno a uno por cada uno de los registros que cumplan la condición de la cláusula WHERE y los irá almacenando gracias a la sentencia APPEND dentro de nuestra tabla interna.
El mayor inconveniente de
trabajar con la forma SELECT...ENDSELECT es que la lectura se hace linealmente,
es decir, SAP debe pasar por cada uno de los registros individualmente hasta
llegar al final. Esto hace que la búsqueda de datos sea muy ineficiente en
términos de rendimiento y alarga innecesariamente el tiempo de ejecución del
programa.
Una forma de mejorar el
rendimiento sería no utilizar la cláusula (*) sino indicar específicamente los
campos que necesitamos llenar. He aquí donde radica la eficiencia de los
programas Estándar que utilizan en su mayoría SELECT...ENDSELECT.
SELECT carrid connid fldate planetype FROM sflight
INTO (i_vuelos-carrid,
i_vuelos-connid, i_vuelos-fldate, i_vuelos-planetype)
WHERE carrid IN s_carrid.
APPEND i_vuelos. CLEAR
i_vuelos.
ENDSELECT.
Al no usar todos los campos
mejoramos el rendimiento y con la cláusulo INTO asignamos directamente el valor
al campo de la tabla interna.
Nota:
En las mejores prácticas de SAP se indica evitar el uso
del SELECT...ENDSELECT, reemplazándolo por el bucle LOOP.
Otra
forma de sentencia select, ojo no son bucles
.
Existe otra forma de la
sentencia SELECT mucho más eficiente nos permite almacenar los datos en la
tabla interna sin necesidad de utilizar la sentencia APPEND. El mismo efecto
que en el caso anterior lo obtendríamos usando...
SELECT * FROM sflight
INTO CORRESPONDING FIELDS OF TABLE
i_vuelos
WHERE carrid IN s_carrid.
Seguimos utilizando el valor
(*) para leer todos los campos.
La claúsula INTO
CORRESPONDING FIELDS OF TABLE compara el nombre del campo de la tabla de SAP
con cada nombre de la tabla interna. Si encuentra coincidencia le asigna su
valor correspondiente. Por eso, es tan importante que el nombre de los campos
de una tabla interna sean iguales al nombre de los campos de una tabla SAP. De
lo contrario, esta forma no se puede utilizar.
Se mantiene la cláusula WHERE. Se elimina la sentencia APPEND
ya que la lectura deja de ser secuencial sino en bloques. Es decir, SAP ya no
tiene que recorrer uno a uno todos los registros, sino que toma el bloque de
registros que coinciden con la condición determinada a través de la cláusula WHERE
y lo asigna en bloque a la tabla interna.
Y aún, otra variación que podemos utilizar sería:
SELECT carrid connid fldate planetype
FROM sflight
INTO TABLE i_vuelos
WHERE carrid IN s_carrid.
Esta
forma es todavía más eficiente ya que:
Evita el uso de (*) y en su
lugar sólo toma el valor de los campos que nos interesa (carrid, connid, fldate
y planetype).
La cláusula INTO TABLE
asigna estos cuatro campos a los cuatro primeros campos de la tabla interna.
Así que, cuidado, el orden en que se hayan declarado estos campos en la tabla
interna es importante. Aquí no hay asignación por nombre de campo, sino por
posición, el valor del campo carrid de la tabla sflight se asignará al primer
campo de la tabla interna, el valor del campo connid de la tabla sflight se
asignará al segundo campo de la tabla interna, y así sucesivamente. Aquí ya no
es tan importante el nombre de los campos de la tabla interna, pero sí la
longitud y el tipo de esos campos. Si no lo tenemos cuenta nuestro programa
acabar abruptamente con dump breve.
Bucle
LOOP- ENDLOOP “Bucle en las tablas internas”
Esta sentencia nos permite
recorrer uno a uno todos los registros que hemos guardado previamente en
nuestra tabla interna. La forma en que la tratamos varía dependiendo de si
hemos declarado nuestra tabla interna con cabecera o sin cabecera.
La
sentencia loop...endloop en tablas internas con cabecera
No necesitan de ninguna
variable adicional. Simplemente llamamos a nuestra tabla interna mediante la
sentencia loop...endloop. En ese mismo momento, todos los registros de cada
línea se cargan sobre la cabecera de la propia tabla interna.
LOOP AT
<tabla_interna>.
* Acción sobre <tabla_interna>
ENDLOOP.
La
sentencia loop...endloop en tablas internas sin cabecera
Necesitan de una variable
estructura adicional donde se contenga el valor de cada registro de la tabla
interna. Al hacer una llamada loop...endloop, el valor del registro por el que
pasa se ha de traspasar a esta variable adicional.
LOOP AT
<tabla_interna> into <estructura>.
* Acción sobre <estructura>
ENDLOOP.
La
sentencia write
Sirve para
"escribir" los datos de cada uno de los registros de nuestra tabla
interna en la pantalla del ordenador y que sean visibles por el usuario. Por
ejemplo, dentro de nuestra sentencia loop...enloop, cada uno de los registros
se irían escribiendo uno a uno en pantalla gracias a la sentencia write.
LOOP AT
<tabla_interna>.
write: <tabla_interna>
ENDLOOP.
Sin embargo, si lo que
queremos no es escribir todos los campos de cada registro, sino sólo algunos
campos de cada registro entonces lo haríamos del siguiente modo:
LOOP AT
<tabla_interna>.
write: / <tabla_interna>-campo1,
<tabla_interna>-campo2.
<tabla_interna>-campo3.
...
ENDLOOP.
La clásula "/"
indica a SAP que todos los registros que siguen a continuación se han de
escribir en una línea diferente. De otro modo, cada registro se montaría uno
encima de otro y sólo se vería impreso en pantalla el último registro.
Por supuesto, la sentencia Write tiene muchas y variadas cláusulas. Algunas de ellas son:
- Write <variable> DD/MM/YYYY: formatea las variables de tipo fecha para que el campo de salida se vea en la forma día/mes/año.
- Write <variable> unit <unidad>: si el campo <variable> es una cantidad se imprimirá en pantalla según la unidad definida.
- Write <variable> left-justified | centered | right-justified: escribe el campo a la izquierda, derecha o centro.
- Write <variable> no-zero: elimina los ceros a la izquierda del campo.
NOTA: Algo que deben evitar
totalmente es el uso de Select Single dentro de un LOOP esto afectara
rotundamente el rendimiento de su programa. Pueden intentarlo como prueba.
Si tienen alguna duda,
comentario o aporte que realizar estaré muy agradecido.
0 comentarios:
Dí lo que piensas...