Oracle

Estructuras de control en PL/SQL

Por : Jhons_1101
2017-08-25
Tags :
Las estructuras de control nos permiten realizar acciones típicas en nuestros scripts como lo pueden ser los bucles o la toma de decisiones. Permitiendo producir programas bien estructurados. Oracle cuenta con las estructuras de control típicas de los lenguajes de programación.

Condicionales


  • IF, condicional que decide entre sí/no
  • CASE, otro condicional con varias posibilidades

  • Bucles


  • FOR, repetición un determinado número de veces
  • FOR EACH, repetición para un conjunto de elementos
  • WHILE...LOOP, repetición mientras ocurra alguna cosa
  • DO...LOOP, repetición un determinado número de veces


  • Las estructuras de control pueden utilizar cualquiera de estos flujos. En el día a día nos toparemos con este proceso.
    estructuras de control elbauldelcodigo

    1. La estructura de selección comprueba una condición y, a continuación, ejecuta una secuencia de instrucciones en lugar de otra, dependiendo de si la condición es verdadera o falsa. Una condición es cualquier variable o expresión que devuelve un valor BOOLEAN (TRUE o FALSE).
    2. La estructura de iteración ejecuta una secuencia de sentencias repetidamente siempre que una condición sea verdadera.
    3. La estructura de secuencia simplemente ejecuta una secuencia de instrucciones en el orden en que se producen.
    compartir en facebook compartir en Google compartir en Twitter compartir en Blogger compartir como código embebido compartir la url

    Condicional IF

    La instrucción IF ejecuta una secuencia de instrucciones dependiendo del valor de una condición. Hay tres formas de declaraciones IF:
  • IF-THEN
  • IF-THEN-ELSE
  • IF-THEN-ELSIF.
  • Para una descripción de la sintaxis de la instrucción IF-THEN se asocia una condición con una secuencia de declaraciones encerradas por las palabras clave THEN (iniciador) y END IF (finalizador).
    La secuencia de sentencias sólo se ejecuta si la condición es TRUE. Si la condición es FALSE o NULL.

    
    DECLARE
      edad     NUMBER(3) := 0;
      min_edad NUMBER(3) := 18;
      salida   VARCHAR(2000);
    BEGIN
      IF edad  < min_edad THEN
         salida   := '- Debes de ser mayor de edad';
      END IF;
    END;
    
    

    Para una descripción de la sintaxis de la instrucción IF-THEN-ELSE añade la palabra clave ELSE seguida por una secuencia alternativa de sentencia si la condición principal IF no se cumple o retorna NULL.

    La sentencia IF-THEN-ELSE garantiza que se ejecuta una u otra secuencia de sentencias.

    
    DECLARE
      edad     NUMBER(3) := 0;
      min_edad NUMBER(3) := 18;
      salida   VARCHAR(2000);
    BEGIN
      IF edad  < min_edad THEN
         salida   := '- Debes de ser mayor de edad';
      ELSE
         -- código e instrucciones requeridas
      END IF;
    END;
    
    

    Para una descripción de la sintaxis de la instrucción IF-THEN-ELSIF a veces se requiere parametrizar varias alternativas para su proceso.
    Si la primera condición es FALSE o NULL, la cláusula ELSIF comprueba otra condición.
    Una instrucción IF puede tener cualquier número de cláusulas ELSIF. La cláusula final ELSE es opcional.

    Las condiciones se evalúan una a una de arriba hacia abajo. Si cualquier condición es TRUE, su secuencia asociada de sentencias se ejecuta y el control pasa a la siguiente instrucción.

    Si todas las condiciones son falsas (FALSE) o NULL, la secuencia en la cláusula ELSE se ejecuta.

    
    DECLARE
      ventas    NUMBER(8,2) := 20000;
      comision  NUMBER(6,2);
    BEGIN
       IF ventas > 50000 THEN
          comision := 1500;
       ELSIF ventas > 35000 THEN
          comision := 500;
       ELSE
          comision := 100;
       END IF;
    END;
    
    

    Si el valor de las ventas es superior a 50000, las condiciones primera y segunda son TRUE. Sin embargo, la comisión se asigna será de 1500 porque la segunda condición nunca se prueba. Cuando la primera condición es TRUE, su instrucción asociada se ejecuta descartando las demás.

    Condicional CASE

    Al igual que la instrucción IF, la instrucción CASE selecciona una secuencia de instrucciones para ejecutar. Sin embargo, Para seleccionar la secuencia, la instrucción CASE utiliza un selector en lugar de varias expresiones booleanas.
    Un selector es una expresión cuyo valor se utiliza para seleccionar una de varias alternativas.
    La sentencia CASE es más legible y más eficiente. La instrucción CASE comienza con la palabra clave CASE La palabra clave es seguida de una variable a ser evaluada. La expresión del selector se evalúa sólo una vez, El selector es seguido por una o más cláusulas WHEN, que se comprueban secuencialmente.

    El valor del selector determina la cláusula que se ejecuta. Si el valor del selector es igual al valor de una expresión WHEN, esta cláusula WHEN se ejecuta. La ejecución nunca cae; Si se ejecuta cualquier cláusula WHEN, el control pasa a la siguiente instrucción.

    La cláusula ELSE funciona de manera similar a la cláusula ELSE en una declaración IF, si no se ejecuta ninguna de los CASE, por defecto entrará y ejecutará el ELSE.

    La cláusula ELSE es opcional. Sin embargo, si omite la cláusula ELSE, PL/SQL agrega la siguiente cláusula implícita ELSE (ELSE RAISE CASE_NOT_FOUND;). Las palabras clave END CASE terminan la instrucción CASE. Estas dos palabras clave deben estar separadas por un espacio.

    Revisemos este ejemplo...


    
    DECLARE
      calificacion CHAR(1);
    BEGIN
      calificacion := 'B';
      CASE calificacion
        WHEN 'A' THEN DBMS_OUTPUT.PUT_LINE('Excelente');
        WHEN 'B' THEN DBMS_OUTPUT.PUT_LINE('Sobresaliente');
        WHEN 'C' THEN DBMS_OUTPUT.PUT_LINE('Aceptable');
        WHEN 'D' THEN DBMS_OUTPUT.PUT_LINE('deficiente');
        WHEN 'F' THEN DBMS_OUTPUT.PUT_LINE('Insuficiente');
        ELSE DBMS_OUTPUT.PUT_LINE('No hay calificación disponible');
      END CASE;
    END;
    
    

    Si se ejecuta cualquier cláusula WHEN, el control pasa a la siguiente instrucción, de modo que las condiciones de búsqueda subsiguientes no se evalúan.
    Al omitir la cláusula ELSE en un CASE se PL ejecutara el error (CASE_NOT_FOUND), miremos como sería.

    estructuras de control CASE
    
    DECLARE
      calificacion CHAR(1);
    BEGIN
      calificacion := 'X';
      BEGIN
        CASE calificacion
           WHEN 'A' THEN DBMS_OUTPUT.PUT_LINE('Excelente');
           WHEN 'B' THEN DBMS_OUTPUT.PUT_LINE('Sobresaliente');
           WHEN 'C' THEN DBMS_OUTPUT.PUT_LINE('Aceptable');
           WHEN 'D' THEN DBMS_OUTPUT.PUT_LINE('deficiente');
           WHEN 'F' THEN DBMS_OUTPUT.PUT_LINE('Insuficiente');
         END CASE;
      EXCEPTION
         WHEN CASE_NOT_FOUND THEN
            DBMS_OUTPUT.PUT_LINE('No Se encontró la calificación');
      END;
    END;
    
    


    Bucles e iteradores en PL/SQL

    Las instrucciones LOOP ejecutan una secuencia de instrucciones varias veces. Hay tres formas de instrucciones LOOP:

    Bucles

  • LOOP
  • WHILE-LOOP
  • FOR-LOOP

  • Instrucción LOOP

    La forma más simple de la sentencia LOOP es el bucle básico, que encierra una secuencia de sentencias entre las palabras clave LOOP y END LOOP, de la siguiente manera.

    
    LOOP
      -- SECUENCIA
    END LOOP;
    
    

    Con cada iteración del bucle, se ejecuta la secuencia de sentencias, entonces el control se reanuda en la parte superior del bucle. Utilice una instrucción EXIT para detener el bucle y evitar un bucle infinito. Puede colocar una o más instrucciones EXIT en cualquier parte dentro de un bucle, pero no fuera de un bucle. Hay dos formas de declaraciones EXIT:

  • EXIT
  • EXIT-WHEN


  • Instrucción EXIT

    La instrucción EXIT obliga a un bucle a completar incondicionalmente. Cuando se encuentra una instrucción EXIT, el bucle se completa inmediatamente y el control pasa a la siguiente instrucción.

    Recuerde, la sentencia EXIT debe colocarse dentro de un bucle. Debes de usar RETURN en vez de EXIT cuando esté fuera de una instrucción LOOP.

    
    DECLARE
      iterador NUMBER := 0;
    BEGIN
      LOOP
        iterador := iterador + 1;
        IF iterador > 3 THEN
           EXIT;  -- Sale del loop inmediatamente
        END IF;
      END LOOP;
     -- Al salir del LOOP continua aquí
     DBMS_OUTPUT.PUT_LINE ('Salida: ' || TO_CHAR(iterador));
     IF iterador > 3 THEN
        RETURN;  -- use RETURN en vez de EXIT fuera de un LOOP
     END IF;
     DBMS_OUTPUT.PUT_LINE ('Salida: ' || TO_CHAR(iterador));
     -- Salida: 4
    END;
      -- SECUENCIA
    END LOOP;
    
    

    Como se puede ver al correr este bloque en el LOOP itera hasta el numero ser cuatro (4) y continua con las demás sentencias..


    Instrucción EXIT-WHEN

    La sentencia EXIT-WHEN permite que un bucle se complete condicionalmente.
    Cuando se encuentra la instrucción EXIT, se evalúa la condición en la cláusula WHEN. Si la condición es verdadera, el bucle se completa y el control pasa a la siguiente instrucción después del bucle. La instrucción EXIT-WHEN reemplaza una instrucción IF sencilla. Estas declaraciones son lógicamente equivalentes, pero la instrucción EXIT-WHEN es más fácil de leer y entender.
    Veamos.

    
    DECLARE
      iterador NUMBER := 0;
    BEGIN
     LOOP
        iterador := iterador + 1;
    
        IF iterador > 3 THEN
           EXIT;  -- Sale del loop inmediatamente
        END IF;
        -- Su equivalente
        EXIT WHEN iterador > 10;
        DBMS_OUTPUT.put_line (iterador);
      END LOOP;
    END;
    
    

    En el anterior ejemplo, si ejecutamos el bloque podemos ver que prevalece la condicional IF ya que el iterador primero cumple el IF y sale (EXIT) antes de terminar de ejecutar el EXIT CASE. Supongamos que corremos el siguiente bloque.

    
    DECLARE
      iterador NUMBER := 0;
    BEGIN
     LOOP
        iterador := iterador + 1;
    
        IF iterador > 3 THEN
           DBMS_OUTPUT.put_line ('IF::'||iterador);
           EXIT;  -- Sale del loop inmediatamente
        END IF;
        -- Su equivalente
        EXIT WHEN iterador > 3;
        DBMS_OUTPUT.put_line (iterador);
      END LOOP;
    END;
    
    

    Vamos a encontrar que muestra primero la respuesta del IF ya que en orden se sentencias primero entra al IF y al dar verdadero sale (EXIT) sin importar que el EXIT CASE tiene el mismo valor de pausa. Si intercambiamos las condicionales, veremos que primero corta el EXIT CASE antes de ejecutar el IF.

    
    DECLARE
      iterador NUMBER := 0;
    BEGIN
     LOOP
        iterador := iterador + 1;
    
        EXIT WHEN iterador > 3;
        -- Su equivalente
        IF iterador > 3 THEN
           DBMS_OUTPUT.put_line ('IF::'||iterador);
           EXIT;  -- Sale del loop inmediatamente
        END IF;
        DBMS_OUTPUT.put_line (iterador);
      END LOOP;
    END;
    
    


    Instrucción WHILE-LOOP

    La instrucción WHILE-LOOP ejecuta las sentencias en el cuerpo del bucle siempre y cuando la condición sea verdadera (TRUE).

    
    DECLARE
      condicion NUMBER := 0;
    BEGIN
       WHILE condicion LOOP
         -- Secuencia de declaraciones
       END LOOP;
    END;
    
    

    Antes de cada iteración del bucle, se evalúa la condición.
    Si es TRUE, se ejecuta la secuencia de sentencias, entonces el control se reanuda en la parte superior del bucle.
    Si es FALSE o NULL, el bucle se omite y el control pasa a la siguiente instrucción.

    El número de iteraciones depende de la condición y se desconoce hasta que se complete el bucle. La condición se prueba una a una en la parte superior del bucle, por lo que el bucle puede ejecutar cero veces o un determinado número de veces, siempre afectado por la condicional TRUE.

    Si necesitamos que al menos se ejecute una vez el bucle, podemos definir una variable TRUE y al entrar al bucle cambiarle el estado a FALSE. Con esto garantizamos mínimo una iteración.

    No olvidar asignar un nuevo valor a la variable booleana para evitar un bucle infinito

    
    DECLARE
      condicion NUMBER := 0;
    BEGIN
       WHILE condición = 0 LOOP
         -- Bucle infinito…
         -- tener en cuenta cambiar el estado de la variable, ya
         -- que este bucle se ejecutará hasta consumir todo el
         -- espacio de memoria y hacer colapsar tu aplicación.
       END LOOP;
    END;
    
    

    Podemos encontrar una particularidad muy buena cuando se trabaja con bucles anidados y esta es que podemos nombrar los bucles asignándole un etiquetado. PL/SQL nos proporciona esta utilidad para darle semántica a nuestro código fuente y facilitar la lectura…

    Este identificador es opcional pero aporta legibilidad, para su uso, basta con denotar el nombre entre paréntesis angulares dobles <<>> antes de abrir el bucle y al momento de cerrarlo podemos y es recomendado nombrarlo como se muestra a continuación. Tener en cuenta que el nombre que se le asigne al bucle no puede contener espacios, aunque si puede contener acentuaciones (tildes), eñes y algunos caracteres especiales como ‘#’.

    Pero no es recomendado. Lo que si debe de ser coincidente entre el nombre declarado y el cierre en le etiqueta END LOOP;

    De no cumplir con la sintaxis de PL/SQL saldrá un error similar a este.

    Error de sintaxis LOOP PL/SQL elbauldelcodigo
    Y algo como.
    Error de sintaxis LOOP PL/SQL elbauldelcodigo
    Miremos este ejemplo.
    
    DECLARE
      s      PLS_INTEGER := 0;
      i      PLS_INTEGER := 0;
      j      PLS_INTEGER;
    BEGIN
      <<outer_loop>>
      LOOP
        i := i + 1;
        j := 0;
        <<inner_loop>>
        LOOP
          j := j + 1;
          s := s + i * j; -- suma de los productos
          EXIT inner_loop WHEN (j > 5);
          EXIT outer_loop WHEN ((i * j) > 15);
        END LOOP inner_loop;
      END LOOP outer_loop;
      DBMS_OUTPUT.PUT_LINE('La suma de productos es igual a: ' || TO_CHAR(s));
    END;
    
    

    Instrucción FOR-LOOP


    Los bucles FOR simples iteran sobre un rango especificado de enteros. El número de iteraciones se conoce antes de empezar el bucle.
    El punto doble (..) sirve como operador para especificar el rango.
    El intervalo se evalúa cuando se introduce por primera vez el bucle FOR y nunca se vuelve a evaluar. Si el límite menor es igual al límite mayor, el cuerpo del bucle se ejecuta una única vez.

    
    DECLARE
       x NUMBER;
    BEGIN
       -- ciclo de numeros del 1 al 10
       FOR x IN 1..10 LOOP
        DBMS_OUTPUT.PUT_LINE('X : ' || x);
      END LOOP;
    END;
    
    

    Por defecto, la iteración procede incrementando desde el límite inferior hacia el límite superior. Sin embargo si utiliza la palabra clave REVERSE, la iteración procede descendientemente desde el límite superior hasta el límite inferior.
    Veamos.

    
    DECLARE
       x NUMBER;
    BEGIN
       -- ciclo de numeros del 10 al 1, ya que al tener la propiedad
       -- reverse se inviente el iterador.
       FOR x IN REVERSE 1..10 LOOP
        DBMS_OUTPUT.PUT_LINE('X : ' || x);
      END LOOP;
    END;
    
    

    En los FOR LOOP el iterador puede ser leído y utilizado para cualquier operación, pero no puede ser cambiado ni manipulado. Al tratar de hacer esto arrojará un error de sintaxis (PLS-00363).
    Veamos.

    
    DECLARE
       x NUMBER;
    BEGIN
       -- La asignación mostrará un error al tratar de ejecutarlo.
       FOR x IN REVERSE 1..10 LOOP
    
         IF x < 3 THEN
           DBMS_OUTPUT.PUT_LINE ('X : ' || x);
         ELSE
           x := 2; -- Genera error PLS-00363
         END IF;
    
       END LOOP;
    END;
    
    
    Error for loop Oracle PL/SQL elbauldelcodigo
    Podemos utilizar variables o constantes para declarar el inicio o el final del bucle FOR. Siempre y cuando cumpla con la condición que sea de tipo numérico. Ya sea mayor a cero o menor a este. Pero teniendo en cuenta siempre que si el límite inferior del bucle es más grande que el límite superior, el cuerpo de bucle no se ejecuta y el control pasa a la siguiente instrucción.

    
    DECLARE
       x NUMBER;
       lnu_inicio CONSTANT  NUMBER(2) := 5;
       lnu_final  NUMBER(2) := 20;
    BEGIN
       FOR x IN  lnu_inicio..lnu_final LOOP
           DBMS_OUTPUT.PUT_LINE ('X : ' || x);
       END LOOP;
       DBMS_OUTPUT.PUT_LINE ('Continúa normalmente');
    END;
    
    

    En el caso anterior, las sentencias se ejecutan con normalidad pues cumple con las dos (2) reglas anteriores.

    
    DECLARE
       x NUMBER;
       lnu_inicio CONSTANT  NUMBER(2) := 10;
       lnu_final  NUMBER(2) := 3;
    BEGIN
       FOR x IN  lnu_inicio..lnu_final LOOP
           DBMS_OUTPUT.PUT_LINE ('X : ' || x);
       END LOOP;
       DBMS_OUTPUT.PUT_LINE ('Continúa normalmente');
    END;
    
    

    Para este caso, solo se ejecutará.
    DBMS_OUTPUT.PUT_LINE ('Continúa normalmente');

    Puesto que no cumple la regla de límite inferior menor a limite superior. Lo que conllevo a que se omitiera el bucle y continuara con las demás sentencias. En este caso el DBMS_OUTPUT.PUT_LINE ('Continúa normalmente').

    Veamos este otro caso. Para ello, podemos utilizar valores menores a cero. No olvidar cumplir con las reglas definidas anteriormente. Para que no nos omita la ejecución del bucle.

    
    DECLARE
       x NUMBER;
       lnu_inicio NUMERIC(2):= -5;
       lnu_final  NUMBER(2) := 2;
    BEGIN
       FOR x IN  lnu_inicio..lnu_final LOOP
           DBMS_OUTPUT.PUT_LINE ('X : ' || x);
       END LOOP;
       DBMS_OUTPUT.PUT_LINE ('Continúa normalmente');
    END;
    
    

    El contador de bucle se define sólo dentro del bucle y no puede hacer referencia a este nombre de variable fuera de él (bucle). Después de que salga ya que el contador de bucle no está definido.

    
    BEGIN
    
      FOR i IN 1..3 LOOP
        DBMS_OUTPUT.PUT_LINE (TO_CHAR(i));
      END LOOP;
      DBMS_OUTPUT.PUT_LINE (TO_CHAR(i)); -- produce error
    END;
    
    

    Error for loop Oracle PL/SQL elbauldelcodigo
    Las mismas reglas de ámbito se aplican a bucles anidados. Adicional a ello se puede utilizar la instrucción EXIT para salir temprano de un bucle FOR.






    Si este contenido te fue útil, no olvides compartirlo en redes sociales, Considéralo. Puede ser la manera de agradecer!


    Agrega tu comentario...

    Puedes utilizar etiquetas <pre></pre>, <p></p>, <div></div>, + (Nombre usuario, para responderle a alguien)

    CSRBMAV





    Este post no tiene comentarios, sé el primero en hacerlo
    Esta entrada no cuenta con imágenes adjuntas

    Unete al grupo de whatsApp +57 316 392 6456

    Sigue el grupo en facebook

    Siguenos.....