0% encontró este documento útil (0 votos)
55 vistas

PL SQL

El documento habla sobre PL/SQL, un lenguaje de programación de bases de datos desarrollado por Oracle. PL/SQL cumple 22 años y sigue siendo popular entre los desarrolladores. El autor escribirá una serie de artículos para ayudar a nuevos desarrolladores a aprender los fundamentos de PL/SQL. Los bloques son las unidades básicas de construcción de programas en PL/SQL y pueden contener declaraciones, código ejecutable y manejo de excepciones.

Cargado por

Freddy Jiron
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
55 vistas

PL SQL

El documento habla sobre PL/SQL, un lenguaje de programación de bases de datos desarrollado por Oracle. PL/SQL cumple 22 años y sigue siendo popular entre los desarrolladores. El autor escribirá una serie de artículos para ayudar a nuevos desarrolladores a aprender los fundamentos de PL/SQL. Los bloques son las unidades básicas de construcción de programas en PL/SQL y pueden contener declaraciones, código ejecutable y manejo de excepciones.

Cargado por

Freddy Jiron
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
Está en la página 1/ 20

Construyendo con Bloques

Parte 1 de una serie de artículos sobre la comprensión y el uso de PL / SQL


Oracle PL / SQL celebra su 22º aniversario en 2011. Lo sé porque estoy viendo la primera guía de usuario de
Oracle PL / SQL publicada; es para PL / SQL Release 1.0, y su fecha de publicación es septiembre de 1989.
Yo trabajaba para Oracle en ese momento, construyendo las primeras herramientas de automatización de
ventas utilizadas por Oracle USA. fuerza de ventas. Ya había trabajado con PL / SQL dentro de SQL Forms 3.0,
pero con el lanzamiento de Oracle 6 Database, PL / SQL estaba disponible como un lenguaje de desarrollo de
aplicaciones independiente.
Tres años después, escribí mi primer libro sobre PL / SQL y desde entonces he hecho poco profesionalmente,
pero he estudiado PL / SQL, escribí mucho código PL / SQL y escribí sobre este lenguaje de programación de
bases de datos, el mejor de su clase. Por supuesto, no fui el único. Miles de desarrolladores de todo el mundo
han estado creando una multitud de aplicaciones basadas en Oracle PL / SQL en las décadas transcurridas
desde su lanzamiento.
Lo mejor de todo es que sigue habiendo una afluencia constante de nuevos desarrolladores de PL / SQL. De
hecho, con la aparición relativamente reciente de India, China y otras naciones como potencias tecnológicas,
he visto a toda una nueva generación de desarrolladores descubrir y trabajar para dominar PL / SQL.
Para ayudar a los recién llegados a PL / SQL a aprovechar al máximo este lenguaje, Oracle Magazine me ha
pedido que escriba una serie de artículos para principiantes de PL / SQL, de los cuales este es el primero. Si
es un desarrollador de PL / SQL experimentado, también puede encontrar estos artículos como un repaso útil
sobre los fundamentos de PL / SQL.
Asumiré para esta serie que aunque mis lectores son nuevos en PL / SQL, han tenido algo de experiencia en
programación y están familiarizados con SQL. Mi enfoque, además, será lograr que los desarrolladores sean
productivos en PL / SQL lo más rápido posible.
¿Qué es PL / SQL?
Para responder a esta pregunta, es importante recordar que cada sitio web que visita, cada aplicación que
ejecuta, se construye a partir de una pila de tecnologías de software. En la parte superior de la pila está la capa
de presentación, las pantallas o dispositivos interactivos con los que el usuario interactúa directamente. (En
estos días, los lenguajes más populares para implementar capas de presentación son Java y .NET). En la parte
inferior de la pila se encuentra el código de máquina que se comunica con el hardware.
En algún lugar en el medio de la pila de tecnología encontrará la base de datos , el software que nos permite
almacenar y manipular grandes volúmenes de datos complejos. La tecnología de base de datos relacional,
construida alrededor de SQL, es la tecnología de base de datos dominante en el mundo actual.
SQL es un lenguaje orientado a conjuntos muy poderoso cuyo único propósito es manipular el contenido de
bases de datos relacionales. Si escribe aplicaciones creadas en Oracle Database, usted (o alguien que escriba
código en un nivel inferior en la pila de tecnología) debe estar ejecutando sentencias SQL para recuperar o
cambiar datos en esa base de datos. Sin embargo, SQL no se puede utilizar para implementar toda la lógica
empresarial y la funcionalidad de usuario final necesaria en nuestras aplicaciones. Eso nos lleva a PL / SQL.
PL / SQL son las siglas de Procedural Language / Structured Query Language . PL / SQL ofrece un conjunto de
comandos de procedimiento (sentencias IF, bucles, asignaciones), organizados en bloques (explicados a
continuación), que complementan y amplían el alcance de SQL.
Ciertamente es posible construir aplicaciones sobre SQL y Oracle Database sin usar PL / SQL. Sin embargo, el
uso de PL / SQL para realizar operaciones específicas de la base de datos, sobre todo la ejecución de
declaraciones SQL, ofrece varias ventajas, incluida una estrecha integración con SQL, un rendimiento mejorado
a través de un tráfico de red reducido y portabilidad (los programas PL / SQL pueden ejecutarse en cualquier
instancia de Oracle Database ). Por lo tanto, el código de front-end de muchas aplicaciones ejecuta tanto
sentencias SQL como bloques PL / SQL, para maximizar el rendimiento mientras se mejora la capacidad de
mantenimiento de esas aplicaciones.
Bloques de construcción de programas PL / SQL PL / SQL es un lenguaje estructurado en bloques. Un
bloque PL / SQL se define mediante las palabras clave DECLARE, BEGIN, EXCEPTION y END, que dividen el
bloque en tres secciones:

1. Declarativo: declaraciones que declaran variables, constantes y otros elementos de código, que luego
se pueden usar dentro de ese bloque
2. Ejecutable: sentencias que se ejecutan cuando se ejecuta el bloque.
3. Manejo de excepciones: una sección especialmente estructurada que puede usar para "capturar" o
capturar cualquier excepción que se genere cuando se ejecuta la sección ejecutable.
Solo se requiere la sección ejecutable. No tiene que declarar nada en un bloque, y no tiene que atrapar las
excepciones generadas en ese bloque.
Un bloque en sí mismo es una declaración ejecutable, por lo que puede anidar bloques dentro de otros bloques.
Aquí hay unos ejemplos:

 El clásico "¡Hola mundo!" El bloque contiene una sección ejecutable que llama al procedimiento
DBMS_OUTPUT.PUT_LINE para mostrar texto en la pantalla:
BEGIN
DBMS_OUTPUT.put_line ('Hello World!');
END;
Las funciones y procedimientos (tipos de bloques con nombre) se analizan más adelante en este artículo con
más detalle, al igual que los paquetes. Sin embargo, brevemente, un paquete es un contenedor para múltiples
funciones y procedimientos. Oracle amplía PL / SQL con muchos paquetes incluidos o integrados.

 El siguiente bloque de ejemplo declara una variable de tipo VARCHAR2 (cadena) con una longitud
máxima de 100 bytes para contener la cadena '¡Hola mundo!'. DBMS_OUTPUT.PUT_LINE luego acepta
la variable, en lugar de la cadena literal, para su visualización:
DECLARE
l_message
VARCHAR2 (100) := 'Hello World!';
BEGIN
DBMS_OUTPUT.put_line (l_message);
END;
Tenga en cuenta que nombré la variable l_message. Generalmente uso el prefijo l_ para las variables locales —
variables definidas dentro de un bloque de código— y el prefijo g_ para las variables globales definidas en un
paquete.

 Este siguiente bloque de ejemplo agrega una sección de excepción que captura cualquier excepción
(CUANDO OTROS) que pueda surgir y muestra el mensaje de error, que es devuelto por la función
SQLERRM (proporcionada por Oracle).
DECLARE
l_message
VARCHAR2 (100) := 'Hello World!';
BEGIN
DBMS_OUTPUT.put_line (l_message);
EXCEPTION
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line (SQLERRM);
END;

 El siguiente bloque de ejemplo demuestra la capacidad de PL / SQL para anidar bloques dentro de
bloques, así como el uso del operador de concatenación (||) para unir varias cadenas.
DECLARE
l_message
VARCHAR2 (100) := 'Hello';
BEGIN
DECLARE
l_message2 VARCHAR2 (100) :=
l_message || ' World!';
BEGIN
DBMS_OUTPUT.put_line (l_message2);
END;
EXCEPTION
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line
(DBMS_UTILITY.format_error_stack);
END;
Ejecución de bloques PL / SQL
Una vez que haya escrito un bloque de código PL / SQL, puede ejecutarlo (ejecutarlo). Hay muchas
herramientas diferentes para ejecutar código PL / SQL. El más básico es SQL * Plus, una interfaz de línea de
comandos para ejecutar sentencias SQL y bloques PL / SQL. La Figura 1 muestra un ejemplo de cómo ejecutar
el más simple de mi "¡Hola mundo!" bloques de ejemplo en SQL * Plus.

Figura 1: Ejecución de Hello World! en SQL * Plus


Lo primero que hago después de conectarme a la base de datos a través de SQL * Plus es activar la salida del
servidor, de modo que las llamadas a DBMS_OUTPUT.PUT_LINE darán como resultado la visualización de
texto en mi pantalla. Luego escribo el código que constituye mi bloque. Finalmente, entro una barra (/) para
decirle a SQL * Plus que ejecute este bloque.
SQL * Plus luego ejecuta el bloque y muestra "¡Hola mundo!" en la pantalla. Oracle proporciona SQL * Plus
como una especie de entorno de mínimo común denominador en el que ejecutar sentencias SQL y bloques PL
/ SQL. Mientras que algunos desarrolladores continúan confiando únicamente en SQL * Plus, la mayoría usa
un entorno de desarrollo integrado (IDE). Entre los más populares de estos IDE (basados en encuestas
informales que realizo en mis sesiones de capacitación) se encuentran

 Desarrollador Oracle SQL, de Oracle


 Toad y SQL Navigator, de Quest Software
 Desarrollador PL / SQL, de Allround Automations
Cada herramienta ofrece ventanas y pasos ligeramente diferentes para crear, guardar y ejecutar bloques PL /
SQL, así como habilitar y deshabilitar la salida del servidor. En esta serie de artículos, solo asumiré que tiene
acceso a SQL * Plus y que ejecutará todas mis declaraciones en una ventana de comandos de SQL * Plus.
¡Nombra esos bloques!
Todos los bloques que les he mostrado hasta ahora son "anónimos", no tienen nombre. Si el uso de bloques
anónimos fuera la única forma en que pudiera organizar sus declaraciones, sería muy difícil usar PL / SQL para
construir una aplicación grande y compleja. En su lugar, PL / SQL es compatible con la definición
de nombre bloques de código, también conocido como subprogramas . Los subprogramas pueden ser
procedimientos o funciones. Generalmente, se usa un procedimiento para realizar una acción y se usa una
función para calcular y devolver un valor. Exploraré los subprogramas con mucho más detalle en un próximo
artículo de esta serie. Por ahora, asegurémonos de que se siente cómodo con los conceptos básicos detrás de
la creación de subprogramas.
Supongamos que necesito mostrar "¡Hola, mundo!" desde varios lugares de mi aplicación. Quiero mucho evitar
repetir la misma lógica en todos esos lugares. Por ejemplo, ¿qué sucede cuando necesito cambiar el mensaje,
tal vez a “¡Hola universo!”? Tendré que encontrar todas las ubicaciones en mi código donde aparece esta lógica.
En su lugar, crearé un procedimiento llamado hello_world ejecutando el siguiente comando de lenguaje de
definición de datos (DDL):
CREATE OR REPLACE PROCEDURE
hello_world
IS
l_message
VARCHAR2 (100) := 'Hello World!';
BEGIN
DBMS_OUTPUT.put_line (l_message);
END hello_world;

En efecto, ahora tengo PL / SQL extendido. Además de llamar a programas creados por Oracle e instalados en
la base de datos (como DBMS_OUTPUT.PUT_LINE), puedo llamar a mi propio subprograma dentro de un
bloque PL / SQL:
BEGIN
hello_world;
END;
He ocultado todos los detalles de cómo saludo al mundo dentro del cuerpo , o implementación, de mi
procedimiento. Ahora puedo llamar a este procedimiento hello_world y hacer que muestre el mensaje deseado
sin tener que escribir la llamada a DBMS_OUTPUT .PUT_LINE o averiguar la forma correcta de formatear la
cadena. Puedo llamar a este procedimiento desde cualquier lugar de mi aplicación. Entonces, si alguna vez
necesito cambiar esa cadena, lo haré en un solo lugar, el único punto de definición de esa cadena.
El procedimiento hello_world es muy simple. Sus procedimientos tendrán mucho más código dentro de ellos y
casi siempre también tendrán parámetros . Los parámetros pasan información a los subprogramas cuando se los
llama y le permiten crear subprogramas que son más flexibles y genéricos. Se pueden utilizar en muchos
contextos diferentes.
Mencioné anteriormente que algún día podría querer mostrar "¡Hola universo!" en lugar de "¡Hola
mundo!" Yo podría hacer una copia de mi procedimiento hola_mundo y cambiar la cadena de muestra:
CREATE OR REPLACE PROCEDURE
hello_universe
IS
l_message
VARCHAR2 (100) := 'Hello Universe!';
BEGIN
DBMS_OUTPUT.put_line (l_message);
END hello_universe;
Sin embargo, podría terminar con docenas de variaciones del "mismo" procedimiento de saludo, lo que hará
que sea muy difícil mantener mi aplicación. Un enfoque mucho mejor es analizar el procedimiento e identificar
qué partes permanecen iguales (son estáticas ) cuando el mensaje necesita cambiar y qué partes
cambian. Luego puedo pasar las partes cambiantes como parámetros y tener un solo procedimiento que se
puede usar en diferentes circunstancias.
Así que cambiaré hello_world (y hello_universe) a un nuevo procedimiento, hello_place:
CREATE OR REPLACE PROCEDURE
hello_place (place_in IN VARCHAR2)
IS
l_message VARCHAR2 (100);
BEGIN
l_message := 'Hello ' || place_in;
DBMS_OUTPUT.put_line (l_message);
END hello_place;
Justo después del nombre del procedimiento, agrego paréntesis de apertura y cierre, y dentro de ellos
proporciono un solo parámetro. Puedo tener varios parámetros, pero cada parámetro sigue la misma forma
básica:
parameter_name parameter_mode datatype
En otras palabras, debe proporcionar un nombre para el parámetro, el modo o la forma en que se usará (IN =
solo lectura) y el tipo de datos que se pasarán al subprograma a través de este parámetro.
En este caso, voy a pasar una cadena para uso de solo lectura al procedimiento hello_place.
Y ahora puedo saludar a mi mundo y a mi universo de la siguiente manera:
BEGIN
hello_place ('World');
hello_place ('Universe');
END;
Más adelante en esta serie, exploraremos el concepto de reutilización y cómo evitar la repetición, pero debería
poder ver en este simple ejemplo el poder de ocultar la lógica detrás de un bloque con nombre.
Ahora suponga que no solo quiero mostrar mis mensajes de "Hola". A veces necesito guardar esos mensajes
en una tabla de base de datos; en otras ocasiones, debo devolver la cadena al entorno del host para mostrarla
en un navegador web. En otras palabras, necesito separar la forma en que se construye el mensaje "Hola" de
la forma en que se usa (se muestra, se guarda, se envía a otro programa, etc.). Puedo lograr este nivel deseado
de flexibilidad moviendo el código que construye el mensaje a su propia función:
CREATE OR REPLACE FUNCTION
hello_message
(place_in IN VARCHAR2)
RETURN VARCHAR2
IS
BEGIN
RETURN 'Hello ' || place_in;
END hello_message;
Este subprograma se diferencia del procedimiento original de la siguiente manera:

 El tipo de programa ahora es FUNCIÓN, no PROCEDIMIENTO.


 El nombre del subprograma ahora describe los datos que se devuelven, no la acción que se realiza.
 El cuerpo o implementación del subprograma ahora contiene una cláusula RETURN que construye el
mensaje y lo devuelve al bloque de llamada.
 La cláusula RETURN después de la lista de parámetros establece el tipo de datos devueltos por la
función.
Con el código necesario para construir el mensaje dentro de la función hello_message, puedo usar este mensaje
de múltiples formas. Puedo, por ejemplo, llamar a la función para recuperar el mensaje y asignarlo a una
variable:
DECLARE
l_message VARCHAR2 (100);
BEGIN
l_message := hello_message ('Universe');
END;
Tenga en cuenta que llamo a la función hello_message como parte de una declaración PL / SQL (en este caso,
una asignación de una cadena a una variable). La función hello_message devuelve una cadena, por lo que
puede usarse en lugar de una cadena en cualquier declaración ejecutable.
También puedo volver a mi procedimiento hello_place y reemplazar el código usado para construir la cadena
con una llamada a la función:
CREATE OR REPLACE PROCEDURE
hello_place (place_in IN VARCHAR2)
IS
BEGIN
DBMS_OUTPUT.put_line
(hello_message (place_in));
END hello_place;
También puedo llamar a la función desde una declaración SQL. En el siguiente bloque, inserto el mensaje en
una tabla de base de datos:
BEGIN
INSERT INTO message_table (message_date, MESSAGE_TEXT)
VALUES (SYSDATE, hello_message('Chicago'));
END;
Aunque la lógica de “hola lugar” es muy simple, demuestra el poder de asignar nombres a una o más
declaraciones ejecutables (un algoritmo) y luego hacer referencia a ese algoritmo simplemente especificando
el nombre y los parámetros requeridos.
Los bloques PL / SQL con nombre permiten construir aplicaciones complejas que pueden entenderse y
mantenerse con relativa facilidad.
Acerca de los nombres en la base de datos Oracle
Ahora que puede ver la importancia de asignar nombres a la lógica, es hora de hablar sobre las reglas
para los nombres (o, para ser más precisos, identificadores) tanto en PL / SQL como, en general, en
Oracle Database.
Estas son las reglas para construir identificadores válidos en Oracle Database:

 La longitud máxima es de 30 caracteres.


 El primer carácter debe ser una letra, pero cada carácter después del primero puede ser una
letra, un número (del 0 al 9), un signo de dólar ($), un guión bajo (_) o un signo de número
(#). Todos los siguientes son identificadores válidos:
hello_world
hello$world
hello#world
Pero estos no son válidos:
1hello_world
hello%world
PL / SQL no distingue entre mayúsculas y minúsculas con respecto a los identificadores. PL / SQL trata
todos los siguientes como el mismo identificador:
hello_world
Hello_World
HELLO_WORLD
Para ofrecerle una mayor flexibilidad, Oracle Database le permite eludir las restricciones de la segunda
y tercera reglas al incluir su identificador entre comillas dobles. Un identificador entre comillas puede
contener cualquier secuencia de caracteres imprimibles, excluidas las comillas dobles; Las diferencias
en el caso también se conservarán. Entonces, todas las siguientes cadenas son identificadores válidos
y distintos:
"Abc"
"ABC"
"ab c"
Rara vez encontrará identificadores entre comillas en código PL / SQL; algunos grupos de desarrollo
los utilizan para ajustarse a sus convenciones de nomenclatura o porque encuentran que las cadenas
de caracteres mixtos son más fáciles de leer.
Estas mismas reglas se aplican a los nombres de los objetos de la base de datos, como tablas, vistas
y procedimientos, con una regla adicional: a menos que ponga entre comillas dobles los nombres de
esos objetos de la base de datos, Oracle Database los almacenará en mayúsculas.
Entonces, cuando creo un procedimiento de la siguiente manera:
CREATE OR REPLACE PROCEDURE
hello_world
IS
BEGIN
DBMS_OUTPUT.put_line
('Hello World!');
END hello_world;
Oracle Database almacena este procedimiento con el nombre HELLO_WORLD.
En el siguiente bloque, llamo a este procedimiento tres veces, y aunque el nombre se ve diferente en
todas las llamadas, todas ejecutan el mismo procedimiento:
BEGIN
hello_world;
HELLO_WORLD;
"HELLO_WORLD";
END;
Oracle Database, por otro lado, no podrá ejecutar mi procedimiento si lo llamo de la siguiente manera:
BEGIN
"hello_world";
END;
Buscará dentro de la base de datos un procedimiento llamado hello_world en lugar de
HELLO_WORLD.
Si no desea que los nombres de sus subprogramas se almacenen en mayúsculas, preceda y siga ese
nombre con comillas dobles cuando cree el subprograma:
CREATE OR REPLACE PROCEDURE
"Hello_World"
IS
BEGIN
DBMS_OUTPUT.put_line
('Hello World!');
END "Hello_World";
Ejecución de SQL dentro de bloques PL / SQL
PL / SQL es un lenguaje de programación de bases de datos. Casi todos los programas que escriba en PL /
SQL leerán o escribirán, o leerán y escribirán en Oracle Database mediante SQL. Aunque esta serie asume un
conocimiento práctico de SQL, debe conocer la forma en que llama a las sentencias SQL desde un bloque PL
/ SQL.
Y aquí hay muy buenas noticias: Oracle Database hace que sea muy fácil escribir y ejecutar declaraciones SQL
en PL / SQL. En su mayor parte, simplemente escribe la declaración SQL directamente en tu bloque PL / SQL
y luego agrega el código necesario para la interfaz entre la declaración SQL y el código PL / SQL.
Supongamos, por ejemplo, que tengo una tabla llamada empleados, con una columna de clave principal,
employee_id y una columna de last_name. Luego puedo ver el apellido del empleado con ID 138, de la siguiente
manera:
SELECT last_name
FROM employees
WHERE employee_id = 138
Ahora me gustaría ejecutar esta misma consulta dentro de mi bloque PL / SQL y mostrar el nombre. Para hacer
esto, necesito "copiar" el nombre de la tabla en una variable local, lo que puedo hacer con la cláusula INTO:
DECLARE
l_name employees.last_name%TYPE;
BEGIN
SELECT last_name
INTO l_name
FROM employees
WHERE employee_id = 138;

DBMS_OUTPUT.put_line (l_name);
END;
Primero declaro una variable local y, al hacerlo, introduzco otra característica elegante de PL / SQL: la capacidad
de anclar el tipo de datos de mi variable a la columna de una tabla. (El anclaje se trata con más detalle más
adelante en esta serie).
Luego ejecuto una consulta en la base de datos, obteniendo el apellido del empleado y depositándolo
directamente en la variable l_name.
Por supuesto, querrá hacer más que ejecutar sentencias SELECT en PL / SQL; querrá poder insertar y actualizar
tablas y eliminarlas también en PL / SQL. A continuación, se muestran ejemplos de cada tipo de declaración de
lenguaje de manipulación de datos (DML):

 Elimine todos los empleados del departamento 10 y muestre cuántas filas se eliminaron:
DECLARE
l_dept_id
employees.department_id%TYPE := 10;
BEGIN
DELETE FROM employees
WHERE department_id = l_dept_id;

DBMS_OUTPUT.put_line (SQL%ROWCOUNT);
END;
Directamente dentro de la declaración DELETE, hago referencia a la variable PL / SQL. Cuando se ejecuta el
bloque, el nombre de la variable se reemplaza con el valor real, 10, y el motor SQL ejecuta DELETE. SQL%
ROWCOUNT es un atributo de cursor especial que devuelve el número de filas modificadas por la declaración
DML ejecutada más recientemente en mi sesión.

 Actualice a todos los empleados del departamento 10 con un aumento salarial del 20 por ciento.
DECLARE
l_dept_id
employees.department_id%TYPE := 10;
BEGIN
UPDATE employees
SET salary = salary * 1.2
WHERE department_id = l_dept_id;

DBMS_OUTPUT.put_line (SQL%ROWCOUNT);
END;

 Insertar nuevo dependiente en la tabla


BEGIN
INSERT INTO employees (employee_id
, last_name
, department_id
, salary)
VALUES (100
, 'Feuerstein'
, 10
, 200000);

DBMS_OUTPUT.put_line (SQL%ROWCOUNT);
END;
Siguiente: Control de la ejecución de bloques
En este artículo, aprendió cómo PL / SQL encaja en el mundo más amplio de Oracle Database. También
aprendió a definir bloques de código que ejecutarán declaraciones PL / SQL y a nombrar esos bloques para
que el código de su aplicación se pueda utilizar y mantener más fácilmente. Finalmente, conoció la ejecución
de declaraciones SQL dentro de PL / SQL.
¿Por qué Nest Blocks?
Puede poner BEGIN antes de cualquier conjunto de una o más declaraciones ejecutables y seguirlo con END,
creando un bloque anidado para esas declaraciones. Hay dos ventajas clave de hacer esto: (1) diferir la
asignación de memoria para las variables necesarias solo dentro de ese bloque anidado, y (2) restringir la
propagación de una excepción generada por una de las declaraciones en el bloque anidado.
Considere el siguiente bloque:
DECLARE
l_message VARCHAR2 (100) := 'Hello';
l_message2 VARCHAR2 (100) := ' World!';
BEGIN
IF SYSDATE >= TO_DATE ('01-JAN-2011')
THEN
l_message2 := l_message || l_message2;
DBMS_OUTPUT.put_line (l_message2);
ELSE
DBMS_OUTPUT.put_line (l_message);
END IF;
END;
Muestra "¡Hola mundo!" cuando la fecha de hoy (devuelta por SYSDATE) es al menos el primer día de 2011; de
lo contrario, solo muestra el mensaje "Hola". Sin embargo, incluso cuando este bloque se ejecuta en 2010,
asigna memoria para la variable l_message2.
Si reestructuro este bloque, la memoria para l_message2 se asignará solo después de 2010:
DECLARE
l_message VARCHAR2 (100) := 'Hello';
BEGIN
IF SYSDATE > TO_DATE ('01-JAN-2011')
THEN
DECLARE
l_message2 VARCHAR2 (100) := ' World!';
BEGIN
l_message2 := l_message || l_message2;
DBMS_OUTPUT.put_line (l_message2);
END;
ELSE
DBMS_OUTPUT.put_line (l_message);
END IF;
END;
De manera similar, puedo agregar una sección de excepción a ese bloque anidado, capturando errores y
permitiendo que el bloque externo continúe ejecutándose:
DECLARE
l_message VARCHAR2 (100) := 'Hello';
BEGIN
DECLARE
l_message2 VARCHAR2 (5);
BEGIN
l_message2 := 'World!';
DBMS_OUTPUT.put_line (
l_message || l_message2);
EXCEPTION
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line (
DBMS_UTILITY.format_error_stack);
END;
DBMS_OUTPUT.put_line (l_message);
END;
En este caso, el bloque anidado generará una excepción VALUE_ERROR, porque l_message2 es demasiado
pequeño (máximo de 5 bytes) para el "World!" cuerda. La sección de excepción del bloque anidado capturará y
mostrará el error. El bloque exterior continuará ejecutándose.
Un artículo futuro de esta serie se centrará en cómo funciona el manejo de excepciones en PL / SQL.
A continuación, en esta serie de artículos, le mostraré cómo controlar el flujo de ejecución en su bloque: lógica
condicional con IF y CASE; lógica iterativa con FOR, WHILE y bucles simples; y plantear y manejar excepciones.
Controlar el flujo de ejecución

Parte 2 de una serie de artículos sobre la comprensión y el uso de PL / SQL


Para ayudar a los recién llegados a PL / SQL a aprovechar al máximo este lenguaje, Oracle
Magazine me ha pedido que escriba una serie de artículos para principiantes de PL / SQL, de los cuales
este es el segundo. Si es un desarrollador de PL / SQL experimentado, puede encontrar estos artículos
como un repaso útil sobre los fundamentos de PL / SQL.

Asumiré para esta serie que aunque los lectores son nuevos en PL / SQL, han tenido algo de experiencia en
programación y están familiarizados con SQL. Mi enfoque, además, será lograr que usted sea productivo en PL
/ SQL lo más rápido posible.

PL / SQL: a sus órdenes


Hay una forma en que PL / SQL es como cualquier otro lenguaje de programación que usará: él (el motor de
tiempo de ejecución de PL / SQL) hace exactamente lo que usted le dice que haga. Cada bloque de código PL
/ SQL que escribe contiene una o más declaraciones que implementan reglas o procesos comerciales
complejos. Cuando ejecuta ese bloque de código, ya sea como un bloque anónimo o un script o llamando a una
unidad de programa almacenada que contiene toda la lógica, Oracle Database sigue las instrucciones que
especifique en ese bloque.
Por tanto, es fundamental saber cómo especificar qué declaraciones deben ejecutarse, en qué circunstancias y
con qué frecuencia. Para hacer esto, Oracle Database ofrece construcciones iterativas y condicionales. Este
artículo le presenta la instrucción IF, la instrucción y expresión CASE, y los diversos tipos de bucles que admite
PL / SQL.

Bifurcación condicional en código


Casi cada fragmento de código que escriba requerirá control condicional , la capacidad de dirigir el flujo de
ejecución a través de su programa, en función de una condición. Esto se hace con las declaraciones IF-THEN-
ELSE y CASE.
También hay expresiones CASE; aunque no es lo mismo que las sentencias CASE , a veces se pueden utilizar
para eliminar por completo la necesidad de una sentencia IF o CASE.
SI. La instrucción IF le permite implementar lógica de ramificación condicional en sus programas. Con él, podrá
implementar requisitos como los siguientes:
Si el salario está entre $ 10,000 y $ 20,000, aplique un bono de $ 1,500.
Si la colección contiene más de 100 elementos, trúnquela.
La declaración IF viene en tres sabores, como se muestra en la Tabla 1 . Echemos un vistazo a algunos
ejemplos de declaraciones IF.

IF Tipo Caracteristicas

Esta es la forma más simple de la declaración IF. La condición entre IF y THEN


SI ENTONCES
determina si se debe ejecutar el conjunto de instrucciones entre THEN y END IF. Si la
TERMINA SI;
condición se evalúa como FALSE o NULL, el código no se ejecutará.

Esta combinación implementa lógica o / o: según la condición entre las palabras clave
SI ENTONCES
IF y THEN, ejecute el código entre THEN y ELSE o entre ELSE y END IF. Se ejecuta
FINALIZA SI;
una de estas dos secciones de declaraciones.
Esta última y más compleja forma de la declaración IF selecciona una condición que es
VERDADERA de una serie de condiciones mutuamente excluyentes y luego ejecuta el
SI ENTONCES
conjunto de declaraciones asociadas con esa condición. Si está escribiendo
ELSIF ELSE END
declaraciones IF como esta en cualquier versión de Oracle Database desde
IF;
Oracle9 I Database Release 1 en adelante, debería considerar el uso de declaraciones
CASE buscadas en su lugar.

Tabla 1: Sabores de declaraciones IF


SI-ENTONCES. La siguiente declaración compara dos valores numéricos. Tenga en cuenta que si uno de estos
dos valores es NULL, la expresión completa devolverá NULL. En el siguiente ejemplo, la bonificación no se
otorga cuando el salario es NULO:
IF l_salary > 40000
THEN
give_bonus (l_employee_id,500);
END IF;
Hay excepciones a la regla de que un NULL en una expresión booleana conduce a un resultado NULL. Algunos
operadores y funciones están diseñados específicamente para tratar con NULL de una manera que conduce a
resultados VERDADEROS y FALSOS (y no NULL). Por ejemplo, puede usar IS NULL para probar la presencia
de un NULL:
IF l_salary > 40000 OR l_salary
IS NULL
THEN
give_bonus (l_employee_id,500);
END IF;
En este ejemplo, "el salario ES NULO" se evalúa como VERDADERO en el caso de que el salario no tenga
valor y, de lo contrario, como FALSO. Los empleados cuyos salarios falten ahora también recibirán
bonificaciones. (Como de hecho probablemente deberían hacerlo, considerando que su empleador fue tan
desconsiderado como para perder la cuenta de su salario en primer lugar).
SI-ENTONCES-ELSE. A continuación, se muestra un ejemplo de la construcción IF-THEN-ELSE (que se basa
en la construcción IF-THEN):
IF l_salary <= 40000
THEN
give_bonus (l_employee_id, 0);
ELSE
give_bonus (l_employee_id, 500);
END IF;
En este ejemplo, los empleados con un salario superior a $ 40 000 obtendrán una bonificación de $ 500,
mientras que los demás empleados no recibirán ninguna bonificación. ¿O lo harán? ¿Qué sucede si el salario,
por cualquier motivo, resulta ser NULO para un empleado determinado? En ese caso, se ejecutarán las
declaraciones que siguen al ELSE y el empleado en cuestión recibirá el bono, que se supone que se destinará
solo a los empleados con salarios altos. Si el salario puede ser NULO, puede protegerse contra este problema
utilizando la función NVL:
IF NVL(l_salary,0) <= 40000
THEN
give_bonus (l_employee_id, 0);
ELSE
give_bonus (l_employee_id, 500);
END IF;
La función NVL devolverá 0 siempre que el salario sea NULO, lo que garantiza que los empleados con un salario
NULO tampoco recibirán ninguna bonificación (esos empleados pobres).
Lo importante a recordar es que una de las dos secuencias de sentencias siempre se ejecutará, porque IF-
THEN-ELSE es una construcción de una u otra. Una vez que se ha ejecutado el conjunto apropiado de
instrucciones, el control pasa a la instrucción que sigue inmediatamente a END IF.
IF-ELSIF. Ahora echemos un vistazo al uso de ELSIF. Esta última forma de la declaración IF es útil cuando
tiene que implementar una lógica que tiene muchas alternativas; no es una situación de una u otra. La
formulación IF-ELSIF proporciona una forma de manejar múltiples condiciones dentro de una sola declaración
IF. En general, debe usar ELSIF con alternativas mutuamente excluyentes (es decir, solo una condición puede
ser VERDADERA para cualquier ejecución de la instrucción IF).
Cada cláusula ELSIF debe tener un ENTONCES después de su condición. (Sólo la palabra clave ELSE no
necesita la palabra clave THEN.) La cláusula ELSE en IF-ELSIF es el "de lo contrario" de la declaración. Si
ninguna de las condiciones se evalúa como TRUE, se ejecutarán las declaraciones de la cláusula ELSE. Pero
la cláusula ELSE es opcional. Puede codificar un IF-ELSIF que solo tenga cláusulas IF y ELSIF. En tal caso, si
ninguna de las condiciones es VERDADERA, no se ejecutará ninguna instrucción dentro del bloque IF.
Aquí hay un ejemplo de una declaración IF-ELSIF que verifica tres condiciones diferentes y contiene una
cláusula ELSE en caso de que ninguna de esas condiciones se evalúe como TRUE.
IF l_salary BETWEEN 10000 AND 20000
THEN
give_bonus(l_employee_id, 1000);
ELSIF l_salary > 20000
THEN
give_bonus(l_employee_id, 500);
ELSE
give_bonus(l_employee_id, 0);
END IF;

CASO: Una alternativa útil a IF


La sentencia y expresión CASE ofrecen otra forma de implementar la ramificación condicional. Al usar CASE
en lugar de IF, a menudo puede expresar las condiciones con mayor claridad e incluso simplificar su código. Hay
dos formas de la declaración CASE:
Sentencia CASE simple. Éste asocia cada una de una o más secuencias de declaraciones PL / SQL con un
valor. La instrucción CASE simple elige qué secuencia de instrucciones ejecutar, basándose en una expresión
que devuelve uno de esos valores.
Sentencia CASE buscada. Éste elige cuál de una o más secuencias de sentencias PL / SQL ejecutar mediante
la evaluación de una lista de condiciones booleanas. Se ejecuta la secuencia de declaraciones asociadas con
la primera condición que se evalúa como VERDADERA.
Además de las declaraciones CASE, PL / SQL también admite expresiones CASE. Una expresión CASE es
similar en forma a una instrucción CASE y le permite elegir cuál de una o más expresiones evaluar. El resultado
de una expresión CASE es un valor único, mientras que el resultado de una declaración CASE es la ejecución
de una secuencia de declaraciones PL / SQL.
Declaraciones CASE simples. Una simple instrucción CASE le permite elegir cuál de varias secuencias de
declaraciones PL / SQL ejecutar, según los resultados de una sola expresión. Las declaraciones CASE simples
toman la siguiente forma:
CASE expression
WHEN result1 THEN
statements1
WHEN result2 THEN
statements2
...
ELSE
statements_else
END CASE;
A continuación, se muestra un ejemplo de una declaración CASE simple que utiliza el tipo de empleado como
base para seleccionar el algoritmo de bonificación adecuado:
CASE l_employee_type
WHEN 'S'
THEN
award_bonus (l_employee_id);
WHEN 'H'
THEN
award_bonus (l_employee_id);
WHEN 'C'
THEN
award_commissioned_bonus (
l_employee_id);
ELSE
RAISE invalid_employee_type;
END CASE;
Esta sentencia CASE tiene una cláusula ELSE explícita, pero ELSE es opcional. Cuando no especifica
explícitamente una cláusula ELSE propia, PL / SQL utiliza implícitamente lo siguiente:
ELSE
RAISE CASE_NOT_FOUND;
En otras palabras, si no especifica una cláusula ELSE y ninguno de los resultados de las cláusulas WHEN
coincide con el resultado de la expresión CASE, PL / SQL generará un error CASE_NOT_FOUND. Este
comportamiento es diferente al de las declaraciones IF. Cuando una instrucción IF carece de una cláusula
ELSE, no ocurre nada cuando no se cumple la condición. Con CASE, la situación análoga conduce a un error.
Declaraciones CASE buscadas. Una instrucción CASE buscada evalúa una lista de expresiones booleanas
y, cuando encuentra una expresión que se evalúa como VERDADERA, ejecuta una secuencia de declaraciones
asociadas con esa expresión. Las declaraciones CASE buscadas tienen la siguiente forma:
CASE
WHEN expression1 THEN
statements1
WHEN expression2 THEN
statements2
...
ELSE
statements_else
END CASE;
Una declaración CASE buscada encaja perfectamente con el problema de implementar mi lógica de
bonificación, como se muestra a continuación:
CASE
WHEN l_salary
BETWEEN 10000 AND 20000
THEN
give_bonus(l_employee_id, 1500);
WHEN salary > 20000
THEN
give_bonus(l_employee_id, 1000);
ELSE
give_bonus(l_employee_id, 0);
END CASE;
Sugerencia: debido a que las cláusulas WHEN se evalúan en orden, es posible que pueda exprimir un poco la
eficiencia adicional de su código enumerando primero las cláusulas WHEN más probables. Además, si tiene
cláusulas WHEN con expresiones “costosas” (es decir, aquellas que requieren muchos ciclos de CPU y
memoria), es posible que desee enumerar las últimas para minimizar las posibilidades de que sean
evaluadas.
Utilice sentencias CASE buscadas cuando desee utilizar expresiones booleanas como base para identificar un
conjunto de sentencias a ejecutar. Use declaraciones CASE simples cuando pueda basar esa decisión en el
resultado de una sola expresión.

Usando expresiones CASE. Una expresión CASE devuelve un único valor, el resultado de la expresión
result_expression elegida. Cada cláusula WHEN debe estar asociada con exactamente una expresión (no
declaración). No utilice punto y coma ni END CASE para marcar el final de la expresión CASE. Las
expresiones CASE terminan con un simple END.

Se puede utilizar una expresión CASE buscada para simplificar el código para aplicar bonificaciones. En lugar
de escribir una declaración IF o CASE con tres llamadas diferentes a give_bonus, puedo llamar a give_bonus
solo una vez y usar una expresión CASE en lugar del segundo argumento:

give_bonus(l_employee_id,
CASE
WHEN l_salary
BETWEEN 10000 AND 20000
THEN 1500
WHEN l_salary > 40000
THEN 500
ELSE 0
END);
A diferencia de la instrucción CASE, no se genera ningún error en el caso de que no se seleccione ninguna
cláusula WHEN en una expresión CASE. En cambio, si no se cumple ninguna condición WHEN, una
expresión CASE simplemente devolverá NULL.

Procesamiento iterativo con bucles


Los bucles en el código le brindan una forma de ejecutar el mismo cuerpo de código más de una vez. Los
bucles son un elemento muy común de programación, porque gran parte de la actividad del mundo real
modelada por nuestros programas implica un procesamiento repetitivo. Podríamos necesitar, por ejemplo,
realizar una operación para cada mes del año anterior. Para citar un ejemplo común de la famosa tabla de
empleados de Oracle, es posible que deseemos actualizar la información de todos los empleados de un
departamento determinado.

PL / SQL proporciona tres tipos de construcciones de bucle:

 El bucle FOR (numérico y cursor)

 El bucle simple (o infinito)

 El bucle WHILE

Cada tipo de lazo está diseñado para un propósito específico con sus propios matices, reglas de uso y pautas
para una construcción de alta calidad.

Para darle una idea de cómo los diferentes bucles resuelven sus problemas de diferentes maneras, considere
los siguientes tres ejemplos de bucles. En cada caso, el procedimiento realiza una llamada a
display_total_sales para un año en particular, para cada año entre los valores del argumento inicial y final.

El bucle FOR. Oracle Database ofrece un bucle FOR numérico y de cursor. Con el ciclo FOR numérico, usted
especifica los valores enteros inicial y final, y PL / SQL hace el resto del trabajo por usted, iterando a través de
cada valor entero entre el inicio y el final y luego terminando el ciclo:

PROCEDURE display_multiple_years (
start_year_in IN PLS_INTEGER
,end_year_in IN PLS_INTEGER
)
IS
BEGIN
FOR l_current_year
IN start_year_in .. end_year_in
LOOP
display_total_sales
(l_current_year);
END LOOP;
END display_multiple_years;
El ciclo de cursor FOR tiene la misma estructura básica, pero con él proporciona un cursor explícito o una
instrucción SELECT en lugar del rango de enteros bajo / alto:
PROCEDURE display_multiple_years (
start_year_in IN PLS_INTEGER
,end_year_in IN PLS_INTEGER
)
IS
BEGIN
FOR l_current_year IN (
SELECT * FROM sales_data
WHERE year
BETWEEN start_year_in
AND end_year_in)
LOOP
display_total_sales
(l_current_year);
END LOOP;
END display_multiple_years;
Tanto en el ciclo FOR numérico como en el del cursor, Oracle Database declara implícitamente el iterador (en
los ejemplos anteriores, es l_current_year) para usted, ya sea como un número entero o un registro. No tiene
que (y no debe) declarar una variable con el mismo nombre, como en
PROCEDURE display_multiple_years (
start_year_in IN PLS_INTEGER
,end_year_in IN PLS_INTEGER
)
IS
l_current_year
INTEGER; /* NOT NEEDED */
BEGIN
FOR l_current_year
IN start_year_in
.. end_year_in
De hecho, si haces declarar una variable tal, no va a ser utilizado por el bucle FOR. Es, más específicamente,
una variable entera diferente a la declarada implícitamente por Oracle Database y usada dentro del cuerpo del
ciclo.

El bucle simple. Se llama simple por una razón: comienza simplemente con la palabra clave LOOP y termina
con la instrucción END LOOP. El bucle terminará si ejecuta EXIT, EXIT WHEN o RETURN dentro del cuerpo
del bucle (o si se genera una excepción).

El Listado 1 presenta un ciclo simple. El Listado 2 presenta un bucle simple que recorre las filas de un cursor
(lógicamente equivalente al bucle FOR del cursor de la sección anterior).

Listado de código 1: un bucle simple

PROCEDURE display_multiple_years (
start_year_in IN PLS_INTEGER
,end_year_in IN PLS_INTEGER
)
IS
l_current_year PLS_INTEGER := start_year_in;
BEGIN
LOOP
EXIT WHEN l_current_year > end_year_in;
display_total_sales (l_current_year);
l_current_year := l_current_year + 1;
END LOOP;
END display_multiple_years;
Compare el ciclo simple basado en cursor en el Listado 2 con el ciclo FOR de cursor. Tenga en cuenta que
debo abrir explícitamente el cursor, buscar el siguiente registro, determinar mediante el uso del atributo de
cursor% NOTFOUND si he terminado de buscar o no, y luego cerrar el cursor después de que finalice el ciclo.
Listado de código 2: un bucle simple que recorre las filas de un cursor
PROCEDURE display_multiple_years (
start_year_in IN PLS_INTEGER
, end_year_in IN PLS_INTEGER)
IS
CURSOR years_cur
IS
SELECT *
FROM sales_data
WHERE year BETWEEN start_year_in AND end_year_in;

l_year sales_data%ROWTYPE;
BEGIN
OPEN years_cur;

LOOP
FETCH years_cur INTO l_year;

EXIT WHEN years_cur%NOTFOUND;

display_total_sales (l_year);
END LOOP;

CLOSE years_cur;
END display_multiple_years;
El ciclo del cursor FOR no requiere ninguno de estos pasos; Oracle Database realiza todos los pasos (abrir,
recuperar, terminar, cerrar) implícitamente.
Aunque no se debe usar un bucle simple para buscar fila por fila a través del conjunto de datos de un
cursor, debe usarse cuando (1) es posible que necesite salir condicionalmente del bucle (con una declaración
EXIT) y (2) desea el cuerpo de el ciclo para ejecutar al menos una vez.
El bucle WHILE. El ciclo WHILE es muy similar al ciclo simple; una diferencia fundamental es que verifica la
condición de terminación por adelantado. Es decir, es posible que un bucle WHILE ni siquiera ejecute su cuerpo
una sola vez. El Listado 3 demuestra el ciclo WHILE.
Listado de código 3: un bucle WHILE
PROCEDURE display_multiple_years (
start_year_in IN PLS_INTEGER
,end_year_in IN PLS_INTEGER
)
IS
l_current_year PLS_INTEGER := start_year_in;
BEGIN
WHILE (l_current_year <= end_year_in)
LOOP
display_total_sales (l_current_year);
l_current_year := l_current_year + 1;
END LOOP;
END display_multiple_years;
El ciclo WHILE consta de una condición (una expresión booleana) y un cuerpo del ciclo. Antes de cada iteración
del cuerpo, Oracle Database evalúa la condición. Si se evalúa como TRUE, se ejecutará el cuerpo del bucle. Si
se evalúa como FALSE o NULL, el bucle terminará.
Luego debe asegurarse de incluir código en el cuerpo del bucle que afectará la evaluación de la condición y, en
algún momento, hará que el bucle se detenga. En el procedimiento del Listado 3 , ese código es
l_current_year := l_current_year + 1
En otras palabras, pase al año siguiente hasta que se muestren las ventas totales de todos los años
especificados.
Si su ciclo WHILE no cambia de alguna manera la forma en que se evalúa la condición, ese ciclo nunca
terminará.
One Way In, One Way Out
En todos los ejemplos de la sección anterior, el bucle FOR requiere claramente la menor cantidad de
código. Generalmente, desea encontrar la implementación más simple y legible para sus requisitos. ¿Eso
significa que siempre debes usar un bucle FOR? De ningún modo.
Usar el bucle FOR es la mejor solución para el escenario descrito porque necesitaba ejecutar el cuerpo del
bucle un número fijo de veces. En muchas otras situaciones, el número de veces que se debe ejecutar un bucle
variará, según el estado de los datos en la aplicación. También es posible que deba terminar el ciclo cuando se
haya producido una determinada condición; en este caso, un bucle FOR no encaja bien.
Un principio importante y fundamental en la programación estructurada es “una entrada, una salida”, es decir,
un programa debe tener un solo punto de entrada y un solo punto de salida. Un solo punto de entrada no es un
problema con PL / SQL; no importa qué tipo de bucle esté utilizando, siempre hay un solo punto de entrada en
el bucle: la primera declaración ejecutable que sigue a la palabra clave LOOP. Sin embargo, es muy posible
construir bucles que tengan múltiples rutas de salida. Evite esta práctica . Tener múltiples formas de terminar
un bucle da como resultado un código que es mucho más difícil de depurar y mantener de lo que sería de otra
manera.
En particular, debe seguir estas dos pautas para la terminación del bucle:
No utilice EXIT o EXIT WHEN en los bucles FOR y WHILE.
Debe usar un bucle FOR solo cuando desee iterar a través de todos los valores (enteros o registros)
especificados en el rango. Una SALIDA dentro de un bucle FOR interrumpe este proceso y subvierte la intención
de esa estructura. Un bucle WHILE, por otro lado, especifica su condición de terminación en la propia
declaración WHILE.
El Listado 4 presenta un ejemplo de un bucle FOR con una salida condicional. Quiero mostrar las ventas totales
de cada año dentro del rango especificado. Sin embargo, si alguna vez encuentro un año con cero ventas
(calculado por la función total_sales_for_year), debería detener el ciclo.
Listado de código 4: un bucle FOR con una salida condicional
PROCEDURE display_multiple_years (
start_year_in IN PLS_INTEGER
, end_year_in IN PLS_INTEGER)
IS
BEGIN
FOR l_current_year IN start_year_in .. end_year_in
LOOP
display_total_sales_for_year (l_current_year);

EXIT WHEN total_sales_for_year (l_current_year) = 0;


END LOOP;
END display_multiple_years;
1- Ahora hay dos formas de "salir" del ciclo. En esta situación, reescribiré el bucle FOR como un bucle
WHILE, lo que significa que ahora también debo declarar el iterador y agregarlo dentro del bucle, como
se muestra en el Listado 5 .
2- No utilice declaraciones RETURN o GOTO dentro de un bucle, ya que provocan la terminación
prematura y no estructurada del bucle.
Listado de código 5: un bucle WHILE con una salida
PROCEDURE display_multiple_years (
start_year_in IN PLS_INTEGER
, end_year_in IN PLS_INTEGER)
IS
l_current_year PLS_INTEGER := start_year_in;
BEGIN
WHILE ( l_current_year <= end_year_in
AND total_sales_for_year (l_current_year) > 0)
LOOP
display_total_sales_for_year (l_current_year);
l_current_year := l_current_year + 1;
END LOOP;
END display_multiple_years;
El Listado 6 presenta un ejemplo de un bucle FOR con un RETURN en él. La función total_sales devuelve las
ventas totales en los años especificados, pero si algún año tiene $ 0 en ventas, la función debe terminar el
ciclo y devolver las ventas totales actuales.

Listado de código 6: Un bucle FOR con dos instancias de RETURN

FUNCTION total_sales (
start_year_in IN PLS_INTEGER
, end_year_in IN PLS_INTEGER)
RETURN PLS_INTEGER
IS
l_return PLS_INTEGER := 0;
BEGIN
FOR l_current_year IN start_year_in .. end_year_in
LOOP
IF total_sales_for_year (l_current_year) = 0
THEN
RETURN l_return;
ELSE
l_return :=
l_return + total_sales_for_year (l_current_year);
END IF;
END LOOP;

RETURN l_return;
END total_sales;
tenga en cuenta que el ciclo termina de una de estas dos formas: iterando a través de todos los números enteros
entre los años de inicio y finalización o ejecutando RETURN dentro del ciclo. Además y relacionado con eso,
esta función ahora tiene dos instancias de RETURN, lo que significa que hay dos formas de “salir” de la
función. Esta tampoco es una forma recomendada de diseñar sus funciones. Debería tener solo un RETORNO
en su sección ejecutable, la última línea de la función.
Puedo reestructurar esta función para que tanto el bucle como la función tengan sólo "una salida", como se
muestra en el Listado 7 .
Listado de código 7: una revisión de bucle con una salida
FUNCTION total_sales (
start_year_in IN PLS_INTEGER
, end_year_in IN PLS_INTEGER)
RETURN PLS_INTEGER
IS
l_current_year PLS_INTEGER := start_year_in;
l_return PLS_INTEGER := 0;
BEGIN
WHILE (l_current_year <= end_year_in
AND total_sales_for_year (l_current_year) > 0)
LOOP
l_return := l_return + total_sales_for_year (l_current_year);
l_current_year := l_current_year + 1;
END LOOP;

RETURN l_return;
END total_sales;
Toda la lógica necesaria para terminar el ciclo está ahora en la condición WHILE, y una vez finalizado el ciclo,
la función ejecuta un único RETORNO para devolver el valor total de ventas. Esta segunda implementación es
ahora más simple y más fácil de entender, y eso es para un programa que en sí mismo ya es bastante
simple. Cuando trabaje con algoritmos mucho más complejos, seguir las pautas de “entrada única, salida única”
tendrá un impacto aún mayor en la legibilidad de su código.
En este artículo, aprendió cómo decirle al compilador PL / SQL que ejecute de manera condicional e iterativa
las declaraciones en su bloque. Este control le permitirá escribir unidades de programa almacenadas que
reflejen el flujo del proceso empresarial definido por sus usuarios.

También podría gustarte