viernes, 5 de marzo de 2021

Oracle 21c - Mejoras al iterador FOR LOOP - Parte #1

El lenguaje PL/SQL de Oracle posee desde sus comienzos una funcionalidad muy utilizada que es el iterador FOR..LOOP. El mismo permite en forma sencilla recorrer una serie de valores consecutivos dentro de un rango dado. Veamos un ejemplo de su funcionalidad:

BEGIN
  FOR NumVar IN 10 .. 12 LOOP
    dbms_output.put_line('Soy el numero ' || TO_CHAR(NumVar));
  END LOOP;
END;
/
Soy el numero 10
Soy el numero 11
Soy el numero 12


PL/SQL procedure successfully completed.

SQL>
No es necesario declarar previamente la variable "NumVar" ni aclarar el incremento deseado (siempre es de a uno). Es posible incluir la palabra clave "REVERSE" antes del rango para que el mismo lo haga en orden reverso, pero hasta Oracle 21c no era posible hacer mucho mas:

BEGIN
  FOR NumVar IN REVERSE 10 .. 12 LOOP
    dbms_output.put_line('Soy el numero ' || TO_CHAR(NumVar));
  END LOOP;
END;
/
Soy el numero 12
Soy el numero 11
Soy el numero 10


PL/SQL procedure successfully completed.

SQL>

Lo nuevo en Oracle 21c



Oracle 21c ofrece algunas opciones adicionales, las cuales vamos a analizar a continuación y en un segundo artículo.

Iteración de valor único

En Oracle 21c Podemos hacer iteraciones de un un solo valor, de la siguiente manera:

BEGIN
  FOR NumVar IN 20 LOOP
    dbms_output.put_line('Soy el numero ' || TO_CHAR(NumVar));
  END LOOP;
END;
/
Soy el numero 20

PL/SQL procedure successfully completed.

SQL>
En si, esta no parece una opción muy interesante, pero lo que le suma utilidad es la posibilidad de usar la clausula REPEAT con la opción WHILE para definir una lógica adicional, como mostramos a continuación:

BEGIN
  FOR NumVar IN 2, REPEAT NumVar * 3 WHILE NumVar < 100 LOOP
    dbms_output.put_line('Soy el numero ' || TO_CHAR(NumVar));
  END LOOP;
END;
/
Soy el numero 2
Soy el numero 6
Soy el numero 18
Soy el numero 54

PL/SQL procedure successfully completed.

Iteraciones Múltiples

Esta opción nos permite definir varios rangos para iterar, de forma tal que la lógica que vamos a ejecutar la definimos en un solo lugar (en nuestro ejemplo, es un simple DBMS_OUTPUT) sin necesidad de crear multiples bloques de iteración:

BEGIN
  FOR NumVar IN 2 .. 4, REVERSE 6 .. 8, 15 .. 16 LOOP
    dbms_output.put_line('Soy el numero ' || TO_CHAR(NumVar));
  END LOOP;
END;
/
Soy el numero 2
Soy el numero 3
Soy el numero 4
Soy el numero 8
Soy el numero 7
Soy el numero 6
Soy el numero 15
Soy el numero 16

PL/SQL procedure successfully completed.

Iteraciones por rango con salto definido por el usuario

Esta opción nos permite controlar el incremento entre cada iteración (antes de Oracle 21c era si o si el valor 1), como vemos a continuación:


BEGIN
  FOR NumVar IN 2 .. 6 BY 2, REVERSE 2 .. 6 BY 2 LOOP
    dbms_output.put_line('Soy el numero ' || TO_CHAR(NumVar));
  END LOOP;
END;
/
Soy el numero 2
Soy el numero 4
Soy el numero 6
Soy el numero 6
Soy el numero 4
Soy el numero 2

PL/SQL procedure successfully completed.

Iteraciones por rango con salto decimal definido por el usuario

Si bien la sintaxis permitía el uso de valores decimales para los valores de inicio y fin del rango, estos eran redondeados a un valor enter en forma automática. Oracle 21c permite definir tanto rangos decimales (manteniendo los incrementos en 1) como también incrementos decimales, como podemos ver en los siguientes ejemplos. 

En este ejemplo, el primer rango tiene comienzo y fin con decimales pero incremento entero:

BEGIN
  FOR NumVar NUMBER(4,1) IN 2.3 .. 4.3 LOOP
    dbms_output.put_line('Soy el numero ' || TO_CHAR(NumVar));
  END LOOP;
END;
/
Soy el numero 2.3
Soy el numero 3.3
Soy el numero 4.3

PL/SQL procedure successfully completed.
Este segundo ejemplo, tanto los valores de inicio / fin del rango como el incremento se define como valor decimal:

BEGIN
  FOR NumVar NUMBER(4,1) IN 2.3 .. 4.3 BY 0.4 LOOP
    dbms_output.put_line('Soy el numero ' || TO_CHAR(NumVar));
  END LOOP;
END;
/
Soy el numero 2.3
Soy el numero 2.7
Soy el numero 3.1
Soy el numero 3.5
Soy el numero 3.9
Soy el numero 4.3

PL/SQL procedure successfully completed.

Lo único que tenemos que tener en cuenta, es definir el tipo de datos de la variable (NumVar) que va a mantener los valores, con un tipo de datos apropiado, como se resalta en los ejemplos.

Salteando valores y deteniendo las iteraciones

La opción WHEN nos permite saltear valores no deseados, por ejemplo si queremos "procesar" solo los números pares en un rango en particular, podemos usar la siguiente sintaxis:

BEGIN
  FOR NumVar IN 3 .. 10 WHEN MOD(NumVar,2) = 0 LOOP
    dbms_output.put_line('Soy el numero ' || TO_CHAR(NumVar));
  END LOOP;
END;
/
Soy el numero 4
Soy el numero 6
Soy el numero 8
Soy el numero 10

PL/SQL procedure successfully completed.

Por otro lado, la opción WHILE (la cual vimos dentro del uso de REPEAT) nos permite definir una condición de salida que detendrá la ejecución del bloque, como podemos ver a continuación:

BEGIN
  FOR NumVar IN 4 .. 20 WHILE NumVar * NumVar < 100 LOOP
    dbms_output.put_line('Soy el numero ' || TO_CHAR(NumVar));
  END LOOP;
END;
/
Soy el numero 4
Soy el numero 5
Soy el numero 6
Soy el numero 7
Soy el numero 8
Soy el numero 9

PL/SQL procedure successfully completed.

Como podemos ver, al evaluar NumVar = 10, la operación NumVar * NumVar da como resultado 100, dejando de cumplir la condición definida en la cláusula WHILE, por lo que el valor 10 no se imprime y el bucle termina.

Lo que sigue

En el próximo artículo veremos en detalles otras mejorar al iterador FOR .. LOOP incluidas en Oracle 21c, que permiten usar el mismo con colecciones PL/SQL.



No hay comentarios.:

Publicar un comentario