Objetivos:
• Definir las excepciones de PL/SQL.
• Reconocer las excepciones no controladas(unhandled exceptions).
• Listar y utilizar los distintos manejadores de excepciones en PL/SQL.
• Atrampar errores no anticipados.
• Describir el efecto de propagación de excepciones en bloques anidados.
• Personalizar los mensajes en excepciones de PL/SQL.
• Definir las excepciones de PL/SQL.
• Reconocer las excepciones no controladas(unhandled exceptions).
• Listar y utilizar los distintos manejadores de excepciones en PL/SQL.
• Atrampar errores no anticipados.
• Describir el efecto de propagación de excepciones en bloques anidados.
• Personalizar los mensajes en excepciones de PL/SQL.
En programación, una excepción es la indicación de un problema que ocurre durante la ejecución de un programa. Sin embargo, la palabra excepción se refiere a que este problema ocurre con poca frecuencia generalmente cuando existe algún dato o instrucción que no se apega al funcionamiento del programa por lo que se produce un error.[1]
Ejemplo:
DECLARE
v_lname VARCHAR2(15);
BEGIN
SELECT last_name INTO v_lname
FROM employees
WHERE first_name = 'John';
DBMS_OUTPUT.PUT_LINE ('El Apellido de John es:' ||v_lname);
END;
---OUTPUT:
Considere el anterior ejemplo. No hay errores de sintaxis en el código, lo que significa que el bloque debería ser capaz de ejecutar con éxito. La sentencia SELECT trata de recuperar el apellido de John,
sin embargo, al ejecutar el código se presenta el siguiente error:
Se espera recuperar sólo una fila; Sin embargo, el SELECT recupera múltiples filas. Tales errores que se producen en tiempo de ejecución se llaman excepciones. Cuando se produce una excepción, el bloque PL/SQL se termina. Puede manejar este tipo de excepciones en su bloque PL/SQL.
Manejando Excepciones.
Ya conocemos cómo escribir bloques PL/SQL con una parte declarativa (que comienza con la palabra clave DECLARE) y una sección ejecutable (que empieza con BEGIN y termina con END).
Para el manejo de excepciones, se incluye otra sección(opcional) llamada: Sección de excepciones.
• Esta sección comienza con la palabra clave EXCEPTION.
• Si está presente, esta debe ser la última sección del bloque PL/SQL.
Ejemplo:
SET SERVEROUTPUT ON
DECLARE
v_lname VARCHAR2(15);
BEGIN
SELECT last_name INTO v_lname
FROM employees
WHERE first_name = 'John';
DBMS_OUTPUT.PUT_LINE ('El Apellido de John es:' ||v_lname);
EXCEPTION
WHEN TOO_MANY_ROWS THEN
DBMS_OUTPUT.PUT_LINE ('Tu consulta retorna mas de un registro. Usa un Cursor.');
END;
---OUTPUT:
Escribimos el mismo ejemplo, pero ahora manejamos la excepción que había ocurrido.
Al añadir la sección excepción, el programa PL/SQL no termina abruptamente. Cuando se produce la excepción, el flujo de ejecución se mueve a la sección de excepciones. Si la excepción ocurrida tiene una condición de control, el bloque PL/SQL finaliza normal, con éxito.
____________________________________________________________________________________
Excepciones en PL/SQL.
Una excepción es un error en PL/SQL, que se propaga durante la ejecución de un bloque. Un bloque siempre termina cuando PL/SQL genera una excepción, pero se puede especificar un manejador de excepciones para realizar acciones finales antes que el bloque finalice.
Métodos para levantar excepciones.
• Se produce un error de Oracle y la excepción asociada se levanta automáticamente. Por ejemplo, cuando ocurre el error ORA-01403, se levanta la excepción NO_DATA_FOUND, la cual indica que la consulta SELECT no retorno ni una fila. Estos errores tienen excepciones predefinidas.
• Dependiendo de la funcionalidad de negocio que implementa su programa, es posible que tenga que levantar una excepción explícitamente. Puede levantar una excepción explícitamente mediante la emisión de la sentencia RAISE en el bloque. Tal excepción puede ser definida por el usuario o predefinida por Oracle. También hay algunos errores de Oracle no predefinidos, para esos errores, se puede declarar excepciones explícitas y asociarlas a ellos.
Capturando Excepciones.
Atrapando una excepción.
Debe incluir una sección de excepciones en su programa PL/SQL para atrapar excepciones. Si la excepción se levanta en la sección ejecutable del bloque, el flujo se mueve al control correspondiente dentro de la sección EXCEPTION. Si PL/SQL maneja con éxito la excepción, está no se propaga al ambiente y el bloque PL/SQL termina con éxito.
Propagar una excepción.
Si la excepción se levanta en la sección ejecutable del bloque y no hay ningún controlador de excepciones correspondiente, el bloque PL/SQL fracasa y la excepción se propaga al entorno de llamada. El entorno de llamada puede ser cualquier aplicación (como SQL*Plus).
Tipos de Excepciones.
Nota: Algunas herramientas/aplicaciónes que interactuan con la Base de Dato Oracle (como Oracle Developer Forms) tienen sus propias excepciones.
Sintaxis:
EXCEPTION
WHEN exception1 [OR exception2 . . .] THEN
statement1;
statement2;
. . .
[WHEN exception3 [OR exception4 . . .] THEN
statement1;
statement2;
. . .]
[WHEN OTHERS THEN
statement1;
statement2;
. . .]
Puede atrapar cualquier error mediante la inclusión de un controlador correspondiente dentro de la sección de control de excepciones del bloque PL/SQL. Cada controlador consiste en una cláusula WHEN, que especifica el nombre de la excepción, seguido de una secuencia de sentencias que se ejecutan cuando se levanta tal excepción.
Puede incluir cualquier número de manejadores dentro de una sección de excepciones para controlar excepciones específicas. Sin embargo, no se puede tener varios controladores para una sola excepción.
En la sintaxis:
Cláusula WHEN OTHERS.
Para atrapar cualquier excepción no especificada, se utiliza el controlador de excepciones OTHERS. Esta opción atrapa cualquier excepción no manejada. Por esta razón, si se utiliza el controlador OTHERS, debe ser el último controlador de excepciones.
Ejemplo:
WHEN NO_DATA_FOUND THEN
statement1;
...
WHEN TOO_MANY_ROWS THEN
statement1;
...
WHEN OTHERS THEN
statement1;
Considere el ejemplo anterior. Si la excepción NO_DATA_FOUND se eleva, las sentencias en el controlador correspondiente se ejecutan; por igual, si se produce la excepción TOO_MANY_ROWS, las sentencias en el controlador correspondiente se ejecutan. Sin embargo, si se levanta alguna otra excepción, son ejecutadas las sentencias en el controlador de excepciones OTHERS.
El controlador OTHERS captura todas las excepciones no manejadas. Algunas herramientas de Oracle tienen sus propias excepciones predefinidas las cuales controlan ciertos eventos en la aplicación. El manejador OTHERS también atrapa a estas excepciones.
Directrices para la captura de excepciones.
• Comience la sección de control de excepciones con la palabra clave EXCEPTION.
• Defina varios controladores de excepciones, cada uno con su propio conjunto de acciones.
• Cuando se produce una excepción, sólo se ejecuta un controlador antes de abandonar el bloque.
• Coloque la cláusula OTHERS después de todas las demás cláusulas de manejo de excepciones.
• Sólo puede haber una cláusula OTHERS.
• Las excepciones no pueden aparecer en las sentencias de asignación o sentencias SQL.
Algunas Excepciones Predefinidas de Oracle.
Capturando Errores No-Predefinidos de Oracle.
Ejemplo:
DECLARE
v_lname VARCHAR2(15);
BEGIN
SELECT last_name INTO v_lname
FROM employees
WHERE first_name = 'John';
DBMS_OUTPUT.PUT_LINE ('El Apellido de John es:' ||v_lname);
END;
---OUTPUT:
Considere el anterior ejemplo. No hay errores de sintaxis en el código, lo que significa que el bloque debería ser capaz de ejecutar con éxito. La sentencia SELECT trata de recuperar el apellido de John,
sin embargo, al ejecutar el código se presenta el siguiente error:
Se espera recuperar sólo una fila; Sin embargo, el SELECT recupera múltiples filas. Tales errores que se producen en tiempo de ejecución se llaman excepciones. Cuando se produce una excepción, el bloque PL/SQL se termina. Puede manejar este tipo de excepciones en su bloque PL/SQL.
Manejando Excepciones.
Ya conocemos cómo escribir bloques PL/SQL con una parte declarativa (que comienza con la palabra clave DECLARE) y una sección ejecutable (que empieza con BEGIN y termina con END).
Para el manejo de excepciones, se incluye otra sección(opcional) llamada: Sección de excepciones.
• Esta sección comienza con la palabra clave EXCEPTION.
• Si está presente, esta debe ser la última sección del bloque PL/SQL.
Ejemplo:
SET SERVEROUTPUT ON
DECLARE
v_lname VARCHAR2(15);
BEGIN
SELECT last_name INTO v_lname
FROM employees
WHERE first_name = 'John';
DBMS_OUTPUT.PUT_LINE ('El Apellido de John es:' ||v_lname);
EXCEPTION
WHEN TOO_MANY_ROWS THEN
DBMS_OUTPUT.PUT_LINE ('Tu consulta retorna mas de un registro. Usa un Cursor.');
END;
---OUTPUT:
Escribimos el mismo ejemplo, pero ahora manejamos la excepción que había ocurrido.
Al añadir la sección excepción, el programa PL/SQL no termina abruptamente. Cuando se produce la excepción, el flujo de ejecución se mueve a la sección de excepciones. Si la excepción ocurrida tiene una condición de control, el bloque PL/SQL finaliza normal, con éxito.
____________________________________________________________________________________
Excepciones en PL/SQL.
Una excepción es un error en PL/SQL, que se propaga durante la ejecución de un bloque. Un bloque siempre termina cuando PL/SQL genera una excepción, pero se puede especificar un manejador de excepciones para realizar acciones finales antes que el bloque finalice.
Métodos para levantar excepciones.
• Se produce un error de Oracle y la excepción asociada se levanta automáticamente. Por ejemplo, cuando ocurre el error ORA-01403, se levanta la excepción NO_DATA_FOUND, la cual indica que la consulta SELECT no retorno ni una fila. Estos errores tienen excepciones predefinidas.
• Dependiendo de la funcionalidad de negocio que implementa su programa, es posible que tenga que levantar una excepción explícitamente. Puede levantar una excepción explícitamente mediante la emisión de la sentencia RAISE en el bloque. Tal excepción puede ser definida por el usuario o predefinida por Oracle. También hay algunos errores de Oracle no predefinidos, para esos errores, se puede declarar excepciones explícitas y asociarlas a ellos.
Capturando Excepciones.
Atrapando una excepción.
Debe incluir una sección de excepciones en su programa PL/SQL para atrapar excepciones. Si la excepción se levanta en la sección ejecutable del bloque, el flujo se mueve al control correspondiente dentro de la sección EXCEPTION. Si PL/SQL maneja con éxito la excepción, está no se propaga al ambiente y el bloque PL/SQL termina con éxito.
Propagar una excepción.
Si la excepción se levanta en la sección ejecutable del bloque y no hay ningún controlador de excepciones correspondiente, el bloque PL/SQL fracasa y la excepción se propaga al entorno de llamada. El entorno de llamada puede ser cualquier aplicación (como SQL*Plus).
Tipos de Excepciones.
Excepción |
Descripción
|
Instrucciones de Manejo
|
Errores Predefinidos de Oracle.
|
Errores que ocurren con frecuencia en PL/SQL.
|
No hay necesidad de declarar esta excepciones. Son predefinidas por Oracle y se levantan de forma implicita.
|
Errores No-Predefinidos de Oracle.
|
Cualquier otro error estándar del servidor de Oracle.
|
Es necesario declararlos dentro de la parte declarativa; el servidor Oracle levanta el error de forma implícita, y luego puedes capturarlo en el controlador de excepciones.
|
Errores definidos por e usuario.
|
X condición que el programador entiende como anormal.
|
Deben ser declarados y levantados de forma explicita.
|
Sintaxis:
EXCEPTION
WHEN exception1 [OR exception2 . . .] THEN
statement1;
statement2;
. . .
[WHEN exception3 [OR exception4 . . .] THEN
statement1;
statement2;
. . .]
[WHEN OTHERS THEN
statement1;
statement2;
. . .]
Puede atrapar cualquier error mediante la inclusión de un controlador correspondiente dentro de la sección de control de excepciones del bloque PL/SQL. Cada controlador consiste en una cláusula WHEN, que especifica el nombre de la excepción, seguido de una secuencia de sentencias que se ejecutan cuando se levanta tal excepción.
Puede incluir cualquier número de manejadores dentro de una sección de excepciones para controlar excepciones específicas. Sin embargo, no se puede tener varios controladores para una sola excepción.
En la sintaxis:
exception
|
Es el nombre una excepción(predefinida por Oracle o definida por el usuario).
|
statement
|
Es una o mas sentencias SQL o PL/SQL.
|
OTHERS
|
Es una cláusula(opcional) de control de excepciones que atrapa cualquier excepción que no ha sido manejada de manera explícita.
|
Para atrapar cualquier excepción no especificada, se utiliza el controlador de excepciones OTHERS. Esta opción atrapa cualquier excepción no manejada. Por esta razón, si se utiliza el controlador OTHERS, debe ser el último controlador de excepciones.
Ejemplo:
WHEN NO_DATA_FOUND THEN
statement1;
...
WHEN TOO_MANY_ROWS THEN
statement1;
...
WHEN OTHERS THEN
statement1;
Considere el ejemplo anterior. Si la excepción NO_DATA_FOUND se eleva, las sentencias en el controlador correspondiente se ejecutan; por igual, si se produce la excepción TOO_MANY_ROWS, las sentencias en el controlador correspondiente se ejecutan. Sin embargo, si se levanta alguna otra excepción, son ejecutadas las sentencias en el controlador de excepciones OTHERS.
El controlador OTHERS captura todas las excepciones no manejadas. Algunas herramientas de Oracle tienen sus propias excepciones predefinidas las cuales controlan ciertos eventos en la aplicación. El manejador OTHERS también atrapa a estas excepciones.
Directrices para la captura de excepciones.
• Comience la sección de control de excepciones con la palabra clave EXCEPTION.
• Defina varios controladores de excepciones, cada uno con su propio conjunto de acciones.
• Cuando se produce una excepción, sólo se ejecuta un controlador antes de abandonar el bloque.
• Coloque la cláusula OTHERS después de todas las demás cláusulas de manejo de excepciones.
• Sólo puede haber una cláusula OTHERS.
• Las excepciones no pueden aparecer en las sentencias de asignación o sentencias SQL.
Algunas Excepciones Predefinidas de Oracle.
Excepción |
Número de Error en Oracle
|
Descripción |
ACCESS_INTO_NULL
|
ORA-06530
|
Intento de asignar valores a los atributos de un objeto no inicializado.
|
CASE_NOT_FOUND
|
ORA-06592
|
No se selecciona ninguna de las opciones en las cláusulas WHEN de una sentencia CASE, y no hay una cláusula ELSE.
|
COLLECTION_IS_NULL
|
ORA-06531
|
Intentado de aplicar un método diferente de EXISTS a una colección(Nested Table, VARRAY) no inicializada.
|
CURSOR_ALREADY_OPEN
|
ORA-06511
|
Intento de abrir un Cursor ya abierto.
|
DUP_VAL_ON_INDEX
|
ORA-00001
|
Intento de insertar un valor duplicado.
|
INVALID_CURSOR
|
ORA-01001
|
Se produjo una operación inválida con un Cursor.
|
INVALID_NUMBER
|
ORA-01722
|
Conversión de carácter a numero fallida.
|
LOGIN_DENIED
|
ORA-01017
|
Intento de iniciar sesión en el servidor de Oracle con un nombre de usuario o contraseña no válidos.
|
NO_DATA_FOUND
|
ORA-01403
|
Sentencia SELECT no retorna datos.
|
NOT_LOGGED_ON
|
ORA-01012
|
El programa PL/SQL emite una llamada de Base de Datos sin estar conectado al servidor de Oracle.
|
PROGRAM_ERROR
|
ORA-06501
|
PL/SQL tiene un problema interno.
|
ROWTYPE_MISMATCH
|
ORA-06504
|
La variable host cursor y la variable PL/SQL envueltas en una asignación tienen tipos incompatibles.
|
STORAGE_ERROR
|
ORA-06500
|
PL/SQL sin memoria o la memoria está dañada.
|
SUBSCRIPT_BEYOND_COUNT
|
ORA-06533
|
Referencia a un elemento de un Nested Table o VARRAY mediante el uso de un índice mayor que el número de elementos de la colección.
|
SUBSCRIPT_OUTSIDE_LIMIT
|
ORA-06532
|
Referencia a un elemento de un Nested Table o VARRAY mediante el uso de un índice que está fuera del rango legal (Ejemplo: –1).
|
SYS_INVALID_ROWID
|
ORA-01410
|
La conversión de una cadena de caracteres a ROWID universal falla porque la cadena de caracteres no representa un ROWID válido.
|
TIMEOUT_ON_RESOURCE
|
ORA-00051
|
Se Agotó el tiempo de espera(Time-Out) mientras el Servidor Oracle esperaba por un recurso.
|
TOO_MANY_ROWS
|
ORA-01422
|
Sentencia SELECT retorna mas de una fila.
|
VALUE_ERROR
|
ORA-06502
|
Se produjo un error: aritmético, de conversión, de truncamiento o de restricción de tamaño.
|
ZERO_DIVIDE
|
ORA-01476
|
Se ha intentado dividir por cero.
|
Las excepciones predefinidas son similares a las No-Predefinidas; sin embargo, estas ultimas no son definidas como excepciones PL/SQL en el servidor Oracle. Mas bien son errores estándar de Oracle y para manejarlos es necesario crear excepciones y asociarlas con dichos errores mediante el uso de la función de PRAGMA EXCEPTION_INIT. Tales excepciones se llaman excepciones no-predefinidas.
Primero debe declarar el error no-predefinido para así poder manejarlo. Una vez declarada, la excepción se levanta de forma implícita. En PL/SQL, PRAGMA EXCEPTION_INIT le dice al compilador que asocie el nombre de la excepción con un número de error Oracle. Esto permite hacer referencia a cualquier excepción interna y así asignar un controlador específico para ella.
Ejemplo:
DECLARE
e_insert_excep EXCEPTION;
PRAGMA EXCEPTION_INIT(e_insert_excep, -01400);
BEGIN
INSERT INTO departments (department_id, department_name)
VALUES (280, NULL);
EXCEPTION
WHEN e_insert_excep THEN
DBMS_OUTPUT.PUT_LINE('INSERCIÓN FALLIDA.');
DBMS_OUTPUT.PUT_LINE(SQLERRM);
END;
/*El ejemplo intenta insertar el valor NULL en la columna de department_name de la tabla departments. Sin embargo, la operación no tiene éxito porque department_name es una columna NOT NULL.*/
---OUTPUT:
El ejemplo ilustra las tres etapas asociadas con la captura de un error no predefinido:
1. Declara el nombre de la excepción en la parte declarativa, utilizando la sintaxis:
excepción_name EXCEPCIÓN;
2. Asocia la excepción declarada con el número de error estándar de Oracle utilizando la función PRAGMA EXCEPTION_INIT. Utilice la siguiente sintaxis:
PRAGMA EXCEPTION_INIT (excepción_name, error_number);
3. Referencia la excepción declarada dentro del control de excepciones correspondiente.
La función SQLERRM se utiliza para recuperar el mensaje de error.
SET SERVEROUTPUT ON
SET VERIFY OFF
DECLARE
e_numero_invalido EXCEPTION;
v_entrada VARCHAR2(4);
v_numero NUMBER;
PRAGMA EXCEPTION_INIT(e_numero_invalido, -06502);
BEGIN
v_entrada := '&numero';
v_numero := v_entrada;
--
DBMS_OUTPUT.PUT_LINE('Tabla del '||v_numero);
FOR i IN 1..12 LOOP
DBMS_OUTPUT.PUT_LINE(v_numero||' X '||i||': '||i*v_numero);
END LOOP;
EXCEPTION
WHEN e_numero_invalido THEN
DBMS_OUTPUT.PUT_LINE('Entrado invalida: '||v_entrada);
DBMS_OUTPUT.PUT_LINE('Debe introducir un valor numérico.');
END;
/*El ejemplo pide al usuario introducir un valor numérico para luego mostrar la tabla de multiplicación de dicho número, si el usuario introduce algo diferente un mensaje de alerta se mostrara en la salida.*/
---OUTPUT:
Funciones relacionas con las Excepciones.
Cuando se produce una excepción, es posible identificar el código o el mensaje de error mediante el uso de dos funciones. Esto nos permite tomar decisiones basadas en X escenario.
• SQLCODE devuelve el número de error Oracle para las excepciones internas.
• SQLERRM devuelve el mensaje asociado con el número de error.
Ejemplo:
CREATE TABLE comision_emp
(
codigo_emp NUMBER(6) CONSTRAINT pk_comi PRIMARY KEY,
comision NUMBER(2,2) NOT NULL,
usuario VARCHAR2(20) NOT NULL,
fecha DATE NOT NULL
);
/*Tabla que usaremos para insertar la comisión de todos los empleados, notar que todos los campos son NOT NULL.*/
---
CREATE TABLE comision_error
(
codigo_error NUMBER,
mensaje_error VARCHAR2(1500),
codigo_emp NUMBER,
usuario VARCHAR2(20),
fecha DATE
);
/*Tabla que usaremos para insertar información sobres las inserciones que no se realizaron en la tabla: comision_emp.*/
---
DECLARE
v_codigo_error NUMBER;
v_mensaje_error VARCHAR2(1500);
--
CURSOR c_comision_emp IS
SELECT employee_id AS emp, commission_pct AS comision
FROM employees;
BEGIN
FOR rec IN c_comision_emp LOOP
BEGIN
INSERT INTO comision_emp
VALUES(rec.emp,rec.comision,USER,SYSDATE);
--
EXCEPTION
WHEN OTHERS THEN
v_codigo_error := SQLCODE;
v_mensaje_error := SQLERRM;
--
INSERT INTO comision_error
VALUES(v_codigo_error,v_mensaje_error,rec.emp,USER,SYSDATE);
END;
END LOOP;
COMMIT;
END;
/*El ejemplo trata de insertar la comisión de cada empleado en la tabla comision_emp, pero dicha tabla tiene todos los campos NOT NULL y no todos los empleados tienen comisión, por lo cual es de esperar errores con algunos registros; para tener control de esto, agregamos un control de excepciones que insertara los registros con errores en la tabla: comision_error. Nota: si ejecuta el SCRIPT dos veces el error cambiaría: ORA-00001: unique constraint (HR.PK_COMI) violated.*/
---OUTPUT:
Cuando una excepción es atrapada en el manejador WHEN OTHERS, puede utilizar un conjunto de funciones genéricas para identificar esos errores. El ejemplo asigna los valores de SQLCODE y SQLERRM a variables, y luego usamos las variables en la sentencia SQL.
Nota: No es posible utilizar SQLCODE o SQLERRM directamente en una instrucción SQL. En su lugar, debe asignar sus valores a variables locales, y luego usar las variables en la sentencia SQL.
____________________________________________________________________________________
Excepciones Definidas por el Usuario.
PL/SQL permite definir sus propias excepciones dependiendo de los requerimientos de su aplicación. Por ejemplo, puede pedir al usuario que introduzca un número de departamento, luego definir una excepción para manejar condiciones de error en los datos de entrada, comprobar si tal número de departamento existe, y si no, es posible que tenga que levantar la excepción definida por el usuario.
Las excepciones definidas por el usuario deben ser:
• Declaradas en la parte declarativa del bloque.
• Levantadas explícitamente con la sentencia RAISE.
• Manejadas en la sección EXCEPTION.
Ejemplo:
SET SERVEROUTPUT ON
DECLARE
v_deptno NUMBER := 500;
v_name VARCHAR2(20) := 'Testing';
e_invalid_department EXCEPTION;
BEGIN
UPDATE departments
SET department_name = v_name
WHERE department_id = v_deptno;
IF SQL%NOTFOUND THEN
RAISE e_invalid_department;
END IF;
COMMIT;
EXCEPTION
WHEN e_invalid_department THEN
DBMS_OUTPUT.PUT_LINE(v_deptno||' No es un número de departamento Valido.');
END;
/*El ejemplo trata de actualizar el department_name de un departamento. Si no existe el número de departamento suministrado, no se actualizan filas en la tabla de departments y ninguna excepción se dispara por defecto; como vemos en el ejemplo, por medio de las excepciones definidas por el usuario, podemos cambiar ese comportamiento, esto permite informar al usuario si la actualización fue exitosa.*/
---
Nota: Utilice la sentencia RAISE dentro del mismo manejador de la excepción para elevar la misma nuevamente y propagar el error al entorno de la llamada.
____________________________________________________________________________________
Excepciones en Bloques Anidados o SubBloques.
Es posible tener tantas secciones EXCEPTION como bloques(BEGIN/END) en tu código; Cuando un subbloque maneja una excepción, este termina normalmente. El control se reanuda al bloque que la contiene inmediatamente después de la instrucción END.
Sin embargo, si PL/SQL levanta una excepción y el bloque actual no tiene un controlador para ella, la excepción se propaga a los bloques padres hasta que encuentra un controlador. Si ninguno de estos bloques controla la excepción, la misma es lanzada al ambiente de llamada.
Cuando una excepción se propaga al bloque padre, las sentencias ejecutables del bloque en cuestión(SubBloque) son pasadas por alto.
Una de las ventajas de este comportamiento es que permite incluir sentencias que manejen sus propios errores dependiendo del bloque, dejando el manejo de excepciones generales a los bloques padres.
Ejemplo:
SET SERVEROUTPUT ON
SET VERIFY OFF
DECLARE
v_entrada VARCHAR2(6);
v_contador NUMBER;
e_bloque_abuelo EXCEPTION;
BEGIN
v_entrada := '&Numero';
v_contador := v_entrada;
v_contador := v_contador+1;
IF v_contador > 3 THEN
RAISE e_bloque_abuelo;
END IF;
--
DECLARE
e_bloque_padre EXCEPTION;
BEGIN
v_contador := v_contador+1;
IF v_contador > 3 THEN
RAISE e_bloque_padre;
END IF;
--
DECLARE
e_bloque_hijo EXCEPTION;
BEGIN
v_contador := v_contador+1;
IF v_contador > 3 THEN
RAISE e_bloque_hijo;
END IF;
EXCEPTION
WHEN e_bloque_hijo THEN
DBMS_OUTPUT.PUT_LINE('Valor: '||v_entrada||', Excepción: e_bloque_hijo');
END;
--
EXCEPTION
WHEN e_bloque_padre THEN
DBMS_OUTPUT.PUT_LINE('Valor: '||v_entrada||', Excepción: e_bloque_padre');
END;
--
EXCEPTION
WHEN e_bloque_abuelo THEN
DBMS_OUTPUT.PUT_LINE('Valor: '||v_entrada||', Excepción: e_bloque_abuelo');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Valor: '||v_entrada||', Para visualizar el ejemplo debe introducir un valor numérico mayor que 0.');
END;
/*El ejemplo muestra como crear programas de PL/SQL con manejo de excepciones por cada subbloque anidado; Este SCRIPT pide al usuario introducir un valor numérico para luego lanzar un excepción basada en el valor introducido.*/
---OUTPUT:
____________________________________________________________________________________
Procedimiento RAISE_APPLICATION_ERROR.
Utilice el procedimiento RAISE_APPLICATION_ERROR para lanzar una excepción predefinida de forma interactiva, excepción que tendrá un código de error no estándar y un mensaje personalizado. Con RAISE_APPLICATION_ERROR, puede reportar errores a la aplicación y evitar devolver excepciones no controladas.
Sintaxis:
RAISE_APPLICATION_ERROR (error_number, message[, {TRUE | FALSE}]);
En la sintaxis:
El procedimiento RAISE_APPLICATION_ERROR se puede utilizar ya sea en la sección ejecutable como en la sección de excepciones de un programa de PL/SQL, o en ambos. El error devuelto es consistente con la forma en que el servidor Oracle produce un error predefinido, no predefinido o definido por el usuario. El número de error y el mensaje se muestran al usuario.
Primero debe declarar el error no-predefinido para así poder manejarlo. Una vez declarada, la excepción se levanta de forma implícita. En PL/SQL, PRAGMA EXCEPTION_INIT le dice al compilador que asocie el nombre de la excepción con un número de error Oracle. Esto permite hacer referencia a cualquier excepción interna y así asignar un controlador específico para ella.
Ejemplo:
DECLARE
e_insert_excep EXCEPTION;
PRAGMA EXCEPTION_INIT(e_insert_excep, -01400);
BEGIN
INSERT INTO departments (department_id, department_name)
VALUES (280, NULL);
EXCEPTION
WHEN e_insert_excep THEN
DBMS_OUTPUT.PUT_LINE('INSERCIÓN FALLIDA.');
DBMS_OUTPUT.PUT_LINE(SQLERRM);
END;
/*El ejemplo intenta insertar el valor NULL en la columna de department_name de la tabla departments. Sin embargo, la operación no tiene éxito porque department_name es una columna NOT NULL.*/
---OUTPUT:
El ejemplo ilustra las tres etapas asociadas con la captura de un error no predefinido:
1. Declara el nombre de la excepción en la parte declarativa, utilizando la sintaxis:
excepción_name EXCEPCIÓN;
2. Asocia la excepción declarada con el número de error estándar de Oracle utilizando la función PRAGMA EXCEPTION_INIT. Utilice la siguiente sintaxis:
PRAGMA EXCEPTION_INIT (excepción_name, error_number);
3. Referencia la excepción declarada dentro del control de excepciones correspondiente.
La función SQLERRM se utiliza para recuperar el mensaje de error.
SET SERVEROUTPUT ON
SET VERIFY OFF
DECLARE
e_numero_invalido EXCEPTION;
v_entrada VARCHAR2(4);
v_numero NUMBER;
PRAGMA EXCEPTION_INIT(e_numero_invalido, -06502);
BEGIN
v_entrada := '&numero';
v_numero := v_entrada;
--
DBMS_OUTPUT.PUT_LINE('Tabla del '||v_numero);
FOR i IN 1..12 LOOP
DBMS_OUTPUT.PUT_LINE(v_numero||' X '||i||': '||i*v_numero);
END LOOP;
EXCEPTION
WHEN e_numero_invalido THEN
DBMS_OUTPUT.PUT_LINE('Entrado invalida: '||v_entrada);
DBMS_OUTPUT.PUT_LINE('Debe introducir un valor numérico.');
END;
/*El ejemplo pide al usuario introducir un valor numérico para luego mostrar la tabla de multiplicación de dicho número, si el usuario introduce algo diferente un mensaje de alerta se mostrara en la salida.*/
---OUTPUT:
Funciones relacionas con las Excepciones.
Cuando se produce una excepción, es posible identificar el código o el mensaje de error mediante el uso de dos funciones. Esto nos permite tomar decisiones basadas en X escenario.
• SQLCODE devuelve el número de error Oracle para las excepciones internas.
• SQLERRM devuelve el mensaje asociado con el número de error.
Ejemplo:
CREATE TABLE comision_emp
(
codigo_emp NUMBER(6) CONSTRAINT pk_comi PRIMARY KEY,
comision NUMBER(2,2) NOT NULL,
usuario VARCHAR2(20) NOT NULL,
fecha DATE NOT NULL
);
/*Tabla que usaremos para insertar la comisión de todos los empleados, notar que todos los campos son NOT NULL.*/
---
CREATE TABLE comision_error
(
codigo_error NUMBER,
mensaje_error VARCHAR2(1500),
codigo_emp NUMBER,
usuario VARCHAR2(20),
fecha DATE
);
/*Tabla que usaremos para insertar información sobres las inserciones que no se realizaron en la tabla: comision_emp.*/
---
DECLARE
v_codigo_error NUMBER;
v_mensaje_error VARCHAR2(1500);
--
CURSOR c_comision_emp IS
SELECT employee_id AS emp, commission_pct AS comision
FROM employees;
BEGIN
FOR rec IN c_comision_emp LOOP
BEGIN
INSERT INTO comision_emp
VALUES(rec.emp,rec.comision,USER,SYSDATE);
--
EXCEPTION
WHEN OTHERS THEN
v_codigo_error := SQLCODE;
v_mensaje_error := SQLERRM;
--
INSERT INTO comision_error
VALUES(v_codigo_error,v_mensaje_error,rec.emp,USER,SYSDATE);
END;
END LOOP;
COMMIT;
END;
/*El ejemplo trata de insertar la comisión de cada empleado en la tabla comision_emp, pero dicha tabla tiene todos los campos NOT NULL y no todos los empleados tienen comisión, por lo cual es de esperar errores con algunos registros; para tener control de esto, agregamos un control de excepciones que insertara los registros con errores en la tabla: comision_error. Nota: si ejecuta el SCRIPT dos veces el error cambiaría: ORA-00001: unique constraint (HR.PK_COMI) violated.*/
---OUTPUT:
Cuando una excepción es atrapada en el manejador WHEN OTHERS, puede utilizar un conjunto de funciones genéricas para identificar esos errores. El ejemplo asigna los valores de SQLCODE y SQLERRM a variables, y luego usamos las variables en la sentencia SQL.
Nota: No es posible utilizar SQLCODE o SQLERRM directamente en una instrucción SQL. En su lugar, debe asignar sus valores a variables locales, y luego usar las variables en la sentencia SQL.
____________________________________________________________________________________
Excepciones Definidas por el Usuario.
PL/SQL permite definir sus propias excepciones dependiendo de los requerimientos de su aplicación. Por ejemplo, puede pedir al usuario que introduzca un número de departamento, luego definir una excepción para manejar condiciones de error en los datos de entrada, comprobar si tal número de departamento existe, y si no, es posible que tenga que levantar la excepción definida por el usuario.
Las excepciones definidas por el usuario deben ser:
• Declaradas en la parte declarativa del bloque.
• Levantadas explícitamente con la sentencia RAISE.
• Manejadas en la sección EXCEPTION.
Ejemplo:
SET SERVEROUTPUT ON
DECLARE
v_deptno NUMBER := 500;
v_name VARCHAR2(20) := 'Testing';
e_invalid_department EXCEPTION;
BEGIN
UPDATE departments
SET department_name = v_name
WHERE department_id = v_deptno;
IF SQL%NOTFOUND THEN
RAISE e_invalid_department;
END IF;
COMMIT;
EXCEPTION
WHEN e_invalid_department THEN
DBMS_OUTPUT.PUT_LINE(v_deptno||' No es un número de departamento Valido.');
END;
/*El ejemplo trata de actualizar el department_name de un departamento. Si no existe el número de departamento suministrado, no se actualizan filas en la tabla de departments y ninguna excepción se dispara por defecto; como vemos en el ejemplo, por medio de las excepciones definidas por el usuario, podemos cambiar ese comportamiento, esto permite informar al usuario si la actualización fue exitosa.*/
---
Nota: Utilice la sentencia RAISE dentro del mismo manejador de la excepción para elevar la misma nuevamente y propagar el error al entorno de la llamada.
____________________________________________________________________________________
Excepciones en Bloques Anidados o SubBloques.
Es posible tener tantas secciones EXCEPTION como bloques(BEGIN/END) en tu código; Cuando un subbloque maneja una excepción, este termina normalmente. El control se reanuda al bloque que la contiene inmediatamente después de la instrucción END.
Sin embargo, si PL/SQL levanta una excepción y el bloque actual no tiene un controlador para ella, la excepción se propaga a los bloques padres hasta que encuentra un controlador. Si ninguno de estos bloques controla la excepción, la misma es lanzada al ambiente de llamada.
Cuando una excepción se propaga al bloque padre, las sentencias ejecutables del bloque en cuestión(SubBloque) son pasadas por alto.
Una de las ventajas de este comportamiento es que permite incluir sentencias que manejen sus propios errores dependiendo del bloque, dejando el manejo de excepciones generales a los bloques padres.
Ejemplo:
SET SERVEROUTPUT ON
SET VERIFY OFF
DECLARE
v_entrada VARCHAR2(6);
v_contador NUMBER;
e_bloque_abuelo EXCEPTION;
BEGIN
v_entrada := '&Numero';
v_contador := v_entrada;
v_contador := v_contador+1;
IF v_contador > 3 THEN
RAISE e_bloque_abuelo;
END IF;
--
DECLARE
e_bloque_padre EXCEPTION;
BEGIN
v_contador := v_contador+1;
IF v_contador > 3 THEN
RAISE e_bloque_padre;
END IF;
--
DECLARE
e_bloque_hijo EXCEPTION;
BEGIN
v_contador := v_contador+1;
IF v_contador > 3 THEN
RAISE e_bloque_hijo;
END IF;
EXCEPTION
WHEN e_bloque_hijo THEN
DBMS_OUTPUT.PUT_LINE('Valor: '||v_entrada||', Excepción: e_bloque_hijo');
END;
--
EXCEPTION
WHEN e_bloque_padre THEN
DBMS_OUTPUT.PUT_LINE('Valor: '||v_entrada||', Excepción: e_bloque_padre');
END;
--
EXCEPTION
WHEN e_bloque_abuelo THEN
DBMS_OUTPUT.PUT_LINE('Valor: '||v_entrada||', Excepción: e_bloque_abuelo');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Valor: '||v_entrada||', Para visualizar el ejemplo debe introducir un valor numérico mayor que 0.');
END;
/*El ejemplo muestra como crear programas de PL/SQL con manejo de excepciones por cada subbloque anidado; Este SCRIPT pide al usuario introducir un valor numérico para luego lanzar un excepción basada en el valor introducido.*/
---OUTPUT:
____________________________________________________________________________________
Procedimiento RAISE_APPLICATION_ERROR.
Utilice el procedimiento RAISE_APPLICATION_ERROR para lanzar una excepción predefinida de forma interactiva, excepción que tendrá un código de error no estándar y un mensaje personalizado. Con RAISE_APPLICATION_ERROR, puede reportar errores a la aplicación y evitar devolver excepciones no controladas.
Sintaxis:
RAISE_APPLICATION_ERROR (error_number, message[, {TRUE | FALSE}]);
En la sintaxis:
error_number
|
Es un número de excepción especificado por el usuario; rango entre –20,000 y –20,999.
|
message
|
Es el mensaje de excepción especificado por el usuario; con longitud máxima de 2,048 bytes.
|
TRUE | FALSE
|
Es un parámetro booleano opcional (Si es TRUE, el error se coloca en la pila de errores anteriores. Si es FALSE(por defecto), el error sustituye a todos los errores anteriores.)
|
Ejemplo:
BEGIN
DELETE FROM comision_emp
WHERE codigo_emp = 100;
--
IF SQL%NOTFOUND THEN
RAISE_APPLICATION_ERROR(-20001, 'Ningún Registro Eliminado.');
ELSE
DBMS_OUTPUT.PUT_LINE(SQL%ROWCOUNT||'Registros Eliminados.');
END IF;
END;
DELETE FROM comision_emp
WHERE codigo_emp = 100;
--
IF SQL%NOTFOUND THEN
RAISE_APPLICATION_ERROR(-20001, 'Ningún Registro Eliminado.');
ELSE
DBMS_OUTPUT.PUT_LINE(SQL%ROWCOUNT||'Registros Eliminados.');
END IF;
END;
/*El ejemplo muestra como usar el procedimiento: RAISE_APPLICATION_ERROR. El SCRIPT trata de eliminar el registro con codigo_emp = 100 de la tabla comision_emp(Creada en ejemplos anteriores), como dicha tabla no contiene este registro, el atributo SQL%NOTFOUND es TRUE por lo cual se ejecuta la sentencia: RAISE_APPLICATION_ERROR*/
---OUTPUT:
---OUTPUT:
_____________________________________________________________________________________