PL SQL
PL SQL
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.
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:
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;
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
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.
IF Tipo Caracteristicas
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.
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.
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).
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;
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);
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.