sábado, 10 de diciembre de 2011

Clase 10.11.2011

select e.numemopleado, e.nombre, o.ciudad
from empleado e, oficina o
where e.numOficina = o.numOficina;


delete from empleado
where salario > 2345;


Select *
from empleado
where upper(cargo)='Gerente'
and salario >= 100000

select *
from Cliente
where upper(direccion) like '%Glasgow%'

trim cargo like 'Gerente'


Resumen comandos:
Borrar tabla
Eliminar registros de una tabla

IN
BETWEEN
UPPER
LOWER
ROUND
VARCHAR2
NUMBER
INTEGER
BOOLEAN
LIKE

viernes, 9 de diciembre de 2011

Clase 09/12/2011

Lista las tablas el usuario conectado.
select * from tab
select * from cat





Crea tabla PERSONA



CREATE TABLE PERSONA
(
ID INTEGER NOT NULL,
NOMBRE VARCHAR2(35),
APELLIDO VARCHAR2(35),
FEC_NACI DATE,
RENTA NUMERIC(5,1)
);


ALTER TABLE PERSONA ADD (
CONSTRAINT PK_PERSONA
PRIMARY KEY
(ID)
);








Insertar datos.
INSERT INTO PERSONA VALUES (1, 'Rodrigo','Salazar',sysdate, 1000);
INSERT INTO PERSONA VALUES (2, 'Paula','Rodriguez',to_date('22/10/1982','dd/mm/yyyy'), 1000.9);

Para eliminar una tabla se utiliza el comando DROP

ejemplo:

DROP VISITA;

create sequence seqPersona

  START WITH 21
  MAXVALUE 999999999999999999999999999
  MINVALUE 1
  INCREMENT BY 1
  NOCYCLE
  CACHE 20
  NOORDER;


select seqPersona.nextval
from dual;

Listar numero de propiedades de todas las propiedades que han sido visitadas

select DISTINCT numpropiedad
from visita
order by numpropiedad


Listar el salario mensual para todos los empleados, mostrando el numero de empleado, nombre, apellido y el detalle del salario


select NUMEMPLEADO,NOMBRE ,SALARIO/12   from empleado

ROUND(SALARIO/12,1)
ROUND es un comando que corta por cantidades de decimales definidos en el parametro ,XX)
si no se pone parametro aproxima y se eliminan los decimales


UPPER cambia todos las letras a mayusculas
LOWER cambia todas las letras a minusculas
TRIM Elimina espacios vacios de los extremos
RTRIM Elimina espacios vacios de la derecha del string
LTRIMElimina espacios vacios de la izquierda del string
TO_NUMBER Convierte un dato alfanumerico en numerico
TO_CHAR Convierte un valor a alfanumerico
TO_DATE Convierte un string en tipo DATE
SUM Suma los valores de un campo
MAX Entrega el valor maximo de un campo
MIN Entrega el valor minimo de un campo
IN Incluye todo lo que esta dentro de la condición
NOT IN no incluye lo que esta dentro de la condición
SUBS

Politicas de buenas practicas para programacion PL/SQL

Declarar, definir el tipo, inicializar y asignar valor por defecto a las estructura dedatos antes de trabajar con ellas.

PL/SQL es un lenguaje fuertemente tipificado. Esto significa que antes de trabajar concualquier tipo de estructura de datos, es necesario declarar las mismas, definir el tipo yopcionalmente inicializarlas o asignarles un valor por defecto.Las declaraciones deben realizarse en la sección de declaración de variables de unbloque anónimo, procedimiento, función o paquete.


En las declaraciones que se relacionan a tablas y columnas utilizar la cláusula

%TYPE y %ROWTYPE

Esta forma permite al código adaptarse a cambios de estructuras de datos y autodocumentarse, ya que al leer el código se puede saber a qué tipo de dato hace referencia.

Para el tipo VARCHAR2 , Oracle separa la memoria necesaria según la longitud definida. Es muy común ‘Hardcodear’ la longitud del mismo a su máxima tamaño para evitar problemas, a costo de utilizar mas memoria de la necesaria. Aquí nuevamente se hace conveniente el uso de %TYPE o %SUBTYPE para un mejor aprovechamiento de los recursos de memoria.

Ejemplo:

Mal:

DECLARE

l_apellidoVARCHAR2(45);

l_mensaje VARCHAR2(2000);

Bien:

DECLARE

l_apellidopersonas.nom_apellido%TYPE;

l_mensaje par_mensajes.mensaje%TYPE;

En los datos numéricos, definir la precisión.

Oracle soporta hasta 38 dígitos de precisión en los tipos NUMBER. Si no se define en forma correcta se está derrochando memoria.

Ejemplo:

Mal:

DECLARE

l_importeNUMBER;

Bien:

DECLARE

l_importeNUMBER(12,2);

Usar declaración de constantes para valores que no cambian durante la ejecución del programa.

Permite que ciertos valores no sean modificados por otros desarrolladores y asegura que los datos que se consideran confidenciales o que se utilizan en fórmulas oparametrizaciones no sean manipulados en los códigos.

Ejemplo:

DECLARE

l_fec_actual DATE := TRUNC(SYSDATE);

l_trj_banco VARCHAR2(4) := ‘VISA’;

Siempre que sea posible, utilizar el tipo de dato

RECORD para manejar estructuras.

La declaración de variables individuales o dispersión de datos, muchas veces, complica la lectura del código. La agrupación de los mismos bajo estructuras, facilita la administración y el mantenimiento del código.

Ejemplo:

Mal:

DECLARE

l_nombre personas.nom_nombre%TYPE;

l_apellido personas.nom_apellido%TYPE;

l_edad personas.num_edad%TYPE;

Bien:

DECLARE TYPE r_persona IS RECORD

(nombre personas.nom_nombre%TYPE,

Apellido personas.nom_apellido%TYPE,

Edad personas.num_edad%TYPE

);

Realizar inicializaciones complejas de variables en la sección de ejecución de programa.

Los errores de un código solo pueden ser capturados en la sección ejecutable de un bloque. Si la inicialización de una variable en la sección de declaración falla, el error no puede ser manejado.

Para ello hay que asegurar que la inicialización lógica no falle y esto se asegura haciendo las inicializaciones al comienzo de la sección de ejecución. Si se produce un error, se puede capturar el error y decidir su tratamiento.

Ejemplo:

Mal:

DECLARE

l_last_calificacion calificaciones.valor%TYPE:=last_busqueda (SYSDATE);

l_min_calificacion INTEGER:=a_calificacion.limits(a_calificacion.low);

BEGIN

Bien:

DECLARE

l_las

t_calificacioncalificaciones.valor%TYPE;

l_min_calificacionINTEGER;

PROCEDURE init IS BEGIN

l_last_calificacion := last_busqueda(SYSDATE);

l_min_calificacion := a_calificacion.limits(a_calificacion.low);

EXCEPTION-- Manejo de errores en el programa.

END;

BEGIN

init;

Reemplazar expresiones complejas con variables booleanas y funciones.

Las expresiones booleanas se pueden evaluar con tres valores: TRUE, FALSE o

NULL. Se pueden usar variables de este tipo para ocultar expresiones complejas. Como consecuencia se puede leer más fácilmente el código y es más simple su mantenimiento.

Ejemplo:

Mal:

IF l_salario_total BETWEEN 10000 AND 50000

AND emp_estado(rec_empleado.numero) = 'N'

AND (MONTHS_BETWEEN (rec_empleado.fec_ingreso, SYSDATE) &~~SPECIAL_REMOVE!#~~gt; 10) THEN

emp_informar(rec_empleado.empno);

END IF;

Bien:

DECLARE

condicion_para_informar BOOLEAN;

BEGIN

condicion_para_informar := total_sal BETWEEN 10000 AND 50000 AND emp_estado(rec_empleado.numero) = 'N'

AND (MONTHS_BETWEEN (rec_empleado.fec_ingreso, SYSDATE) &~~SPECIAL_REMOVE!#~~gt; 10;

.........

IF condicion_para_informar THEN

emp_informar(rec_empleado.empno);

END IF;

EXCEPTION

WHEN OTHERS THEN-- definir el manejo de errors

.

END;

Remover variables y código no usado.

En determinadas circunstancias los códigos son modificados a medida que transcurre el tiempo, la lógica cambia y a veces se declaran variables que no se usan, se escribe código que en un momento era necesario o que se quiere mantener activado por un momento, pero después no se recuerda cual fue el motivo del mismo.

Para mantener todo más claro, es conveniente eliminar esos puntos que conducen a “zonas muertas”. Una práctica para esto consiste en eliminar las variables que solo aparecen en la zona de declaración. Existen varios productos que simplifican esta tarea. Es mucho más simple entender, realizar seguimientos o mantener códigos que no tienen ‘zonas muertas’. A modo de ejemplo se incluye un código con algunos errores:

PROCEDURE check_control (

p_nro_cuenta IN cuentas.nro_cuenta%TYPE,

p_importe IN VARCHAR2) IS

l_contador NUMBER(3);

l_baja BOOLEAN;

l_fecha_movimiento DATE := SYSDATE;

BEGIN

l_fecha_movimiento := r_cuenta.fecha_ult_mov (p_nro_cuenta);

IF ADD_MONTHS (SYSDATE, -60) &~~SPECIAL_REMOVE!#~~gt; l_fecha_movimiento THEN

Informar_cuenta;

ELSIF ADD_MONTHS (SYSDATE, -24) &~~SPECIAL_REMOVE!#~~gt; l_fecha_movimiento THEN

Check_baja (p_nro_cuenta, l_baja);

IF l_baja AND/* agregado para forzar false */

FALSE THENarmar_carta (p_nro_cuenta);

END IF; -- arma proceso para control -- pkg_procesos_cuenta.iniciar_control (p_nro_cuenta);

END IF;

END;

Lo que se puede observar es lo siguiente:

  • p_Importe está declarado, no se usa y no tiene asignación por defecto, por lo cual el valor es totalmente ignorado.
  • l_contador está declarada, pero no se usa.
  • l_fecha_movimiento está asignado con sysdate e inmediatamente recibe el valor der_cuenta.fecha_ult_mov (p_nro_cuenta);.
  • La llamada a armar_carta se desactivo con el agregado de FALSE.
  • La llamada a pkg_procesos_cuenta.iniciar_control esta comentada.

Utilizar rutinas de cierre o limpieza cuando los programas terminan (en ejecución normal o por error)

En algunos escenarios es crucial tener rutinas de cierre o limpieza, las cuales se deben incluir al finalizar el programa y al final de cada excepción. Generalmente son aplicables para el uso de cursores y manejo de archivos. A continuación se muestra ejemplos:

Ejemplo:

Mal:

DECLARE

c_cursor NUMBER(2);

f_file UTL_FILE.FILE_TYPE;

BEGIN

c_cursor := DBMS_SQL.OPEN_CURSOR;

f_file := UTL_FILE.FOPEN (‘c:\temp’,’archivo.txt’, ‘R’);

….

EXCEPTION

WHEN NO_DATA_FOUND THEN

log_error;

RAISE;

END;

Se puede observar que tanto el cursor, como el archivo quedan abiertos en caso de existir alguna excepción.

Bien:

DECLARE

c_cursor NUMBER(2);

f_file UTL_FILE.FILE_TYPE;

PROCEDURE limpiar

IS

IF c_cursor%ISOPEN THEN

DBMS_SQL.CLOSE (c_cursor);

END IF;

UTL_FILE.FCLOSE(f_file);

END limpiar;

BEGIN

c_cursor := DBMS_SQL.OPEN_CURSOR;

f_file := UTL_FILE.FOPEN (‘c:\temp’,’archivo.txt’, ‘R’);

limpiar;

EXCEPTION

WHEN NO_DATA_FOUND THEN

log_error;

limpiar;

raise;

END;

Ahora se puede ver que se definió la rutina que realiza el cierre de archivo y de cursor. Este tipo de práctica evita que se produzcan errores que indiquen que el archivo está en uso o que el cursor ya se encuentra abierto, cuando la rutina es llamada de distintos puntos, además que facilita a otros desarrolladores agregar nuevas estructuras y contemplar el cierre o limpieza de las mismas.

Tener cuidado con las conversiones implícitas de tipos de datos.

Si bien es sabido que PL/SQL maneja las conversiones implícitas, existen al menos dos grandes problemas con esto. Las conversiones no son intuitivas, a veces se realizan de formas no esperadas y ocurren problemas, especialmente dentro de sentencias SQL. Las reglas de conversión no están bajo el control de desarrollador. Pueden cambiar con el upgrade a una versión de Oracle o con el cambio de parámetros como NLS_DATE_FORMAT.

Se puede convertir con el uso explícito de funciones como son:

TO_DATE, TO_CHAR,TO_NUMBER y CAST.

Ejemplo:

Mal:

DECLARE

l_fecha_fin DATE := ’01-MAR-04’;

Este código puede dar error si los parámetros de inicialización no corresponden a DD-MON-YY o DD-MON-RR.

Bien:

DECLARE

l_fecha_fin date := TO_DATE (’01-MAR-04’,’DD-MON-RR’);

En este caso el uso de conversiones explícitas evita errores y no se está sujeto a condicionesexternas del programa.

3. Pauta para declaración y uso de variables de paquetes.

•Agrupar los tipos de datos, evitar su exposición y controlar su manipulación.

Los paquetes requieren ciertos tipos de recaudos en la forma de declaración y uso de variables. Agrupar los tipos de datos, evitar su exposición y controlar su manipulación permiten obtener las ventajas del uso de los mismos.

Definir las constantes que son referenciadas por toda la aplicación en un paquete único.

Definir las constantes que corresponden a un área específica dentro de un paquete que encapsula esa funcionalidad.

Nunca colocar literales ‘en duro’, como ‘SI’ o 150 en el código. Es conveniente crear un paquete para mantener estos nombres y valores publicados en reemplazo de los literales.

Ejemplo para paquete general

CREATE OR REPLACE PACKAGE CONSTANTS IS

-- representación de true o false

falso CONSTANT CHAR(1) := ‘F’;

verdadero CONSTANT CHAR(1) := ‘V’; -- fecha de control (6 meses antes)

fecha_control CONSTANT DATE := ADD_MONTHS (SYSDATE, -6);

Ejemplo para paquete específico

CREATE OR REPLACE PACKAGE cta_constants IS

semana_max CONSTANT INTEGER := 54;

activo CONSTANT CHAR(1) := ‘A’;

inactivo CONSTANT CHAR(1) := ‘I’;

codigo_pais CONSTANT INTEGER := 54;

Este tipo de práctica permite que el código no luzca ‘hard codeado’, lo cual lo hace mas legible y mantenible y además evita que los literales sean modificados.

Centralizar las definiciones de Types en las especificaciones del paquete.

A medida que se usan los features del lenguaje, se definirán distintos

TYPE entre los que podemos incluir:

SUBTYPEs que definen tipos específicos de la aplicación.

Collection TYPEs, como lista de números, fechas y records.

Cursores referenciados.

Esto permite tener estandarizados los tipos de datos para que sean usados por múltiples programas. Los desarrolladores pueden escribir más rápidamente y disminuir los bugs. También simplifica el mantenimiento de los types, ya que solo es necesario el/los paquetes donde están declarados.

Ejemplo

CREATE OR REPLACE PACKAGE colltype IS

TYPE logicos_tab IS TABLE OF BOOLEAN;

TYPE logicos_tab_idx IS TABLE OF BOOLEAN

INDEX BY BINARY_INTEGER;

TYPE fechas_tab IS TABLE OF DATE;

TYPE fechas_tab_idx IS TABLE OF DATE

INDEX BY BINARY_INTEGER;

END colltype;

•Disminuir el uso de variables globales en paquetes y en caso de hacerlo, solo en el cuerpo del paquete.

Una variable global es una estructura de datos que se puede referenciar fuera del alcance o bloque en donde está declarada.

Cuando se declara una variable en un paquete, existe y retiene su valor durante la duración de la sesión. Son peligrosas porque crean dependencias ocultas o efectos laterales. El seguimiento de las mismas es complejo, ya que es necesario ver la implementación para ver sus instancias. Una solución general para esto es pasar estas variables globales como un parámetro para no referenciarlas directamente en el programa.

Ejemplo

FUNCTION obtener_multa ( p_cuenta IN clientes.nro_cuenta%TYPE) IS

l_dias_atrasoNUMBER(3);

BEGIN

l_dias_atraso := determinar_atraso( p_cuenta, SYSDATE);

return (l_dias_atraso * g_tasa_diaria);

END obtener_multa;

En esta función el retorno depende de la variable global g_tasa_diaria. Esto hace que se pierda flexibilidad ya que la función solo puede trabajar con el valor instanciado y además, si no tiene valor, se corre el riesgo de que no trabaje en forma correcta. Para mejorar los resultados y reducir la interdependencia se puede agregar un parámetro:

FUNCTION obtener_multa (

p_cuenta IN clientes.nro_cuenta%TYPE,

P_tasa_diaria IN NUMBER

)

IS

l_dias_atrasoNUMBER(3);

BEGIN

l_dias_atraso := determinar_atraso( p_cuenta, SYSDATE);

return (l_dias_atraso * g_tasa_diaria);

END obtener_multa;

Exponer las variables globales de los paquetes usando ‘get and set’.

Cualquier estructura de datos declarada en la especificación del paquete puede ser referenciada por cualquier programa con autorización de EXECUTE.Esto hace que en forma deliberada se pueda hacer uso de esas estructuras globales.

Para evitar eso, es conveniente declarar estos datos en el cuerpo del paquete y proveer al paquete de métodos get y set, declarados en la especificación. Esta forma le permite a los desarrolladores, acceder a los datos a través de estos programas y manipular los datos según las reglas de estos procedimientos.

Ejemplo

CREATE OR REPLACE PACKAGE pkg_calculo_gastos IS

g_gasto_mensual NUMBER(3):= 20;

FUNCTION dias_atraso (p_cuenta IN CTA.nro_cuenta%TYPE)

RETURN INTEGER;

END pkg_calculo_gastos;

Fácilmente podemos manipular los datos desde cualquier lugar haciendo mención a:

BEGIN

pkg_calculo_gastos.g_gasto_mensual := 15;

….

Para evitar esto y poder manipular los datos según las reglas del negocio se puede reescribir el código agregando ‘set’ y ‘get’ de esta manera:

CREATE OR REPLACE PACKAGE pkg_calculo_gastos IS

FUNCTION dias_atraso (p_cuenta IN cuentas.nro_cuenta%TYPE)

RETURN INTEGER;

PROCEDURE set_gasto_mensual (p_gasto IN NUMBER);

END pkg_calculo_gastos;

CREATE OR REPLACE PACKAGE BODY pkg_calculo_gastos

IS

g_gasto_mensual := 15;

PROCEDURE set_gasto_mensual (p_gasto IN NUMBER)

IS

BEGIN

g_gasto_mensual := GREATEST (LEAST (p_gasto, 30), 10);

END set_gasto_mensual;

END pkg_calculo_gastos;


Pautas para el uso de estructuras de Control

Las estructuras de control pueden convertirse en un punto de complejidad de un código. La normalización del uso de RETURN y el EXIT garantiza rapidez en la comprensión de las lógicas escritas y facilidad en su mantenimiento.

•Nunca se sale de una estructura repetitiva con RETURN o con EXIT.

Cada estructura repetitiva tiene un punto de control por donde se debe producir su salida.

Un FOR loop itera desde el valor de comienzo hasta el valor de terminación(ciclo N).

•Un WHILE loop itera mientras no se cumpla la condición de terminación. (Ciclo0).

•Existe un LOOP con control de la condición al final de ciclo (ciclo 1). Es LOOP …EXIT WHEN condición lógica.

Combinando estos ciclos se puede hacer que las estructuras tengan un único punto de control para el ciclo repetitivo. Esto facilita la lectura, comprensión y mantenimiento del programa y permite hacer modificaciones en forma más simple.

Una función debe tener un único RETURN exitoso como última línea de la sección ejecutable. Normalmente, cada manejador de excepciones puede retornar un valor.

En los programas largos donde se evalúan muchas condiciones, la existencia de múltiples salidas dificulta el entendimiento y mantenimiento del código.

Ejemplo

LOOP

read_line (file1, line1, file1_eof);

read_line (file2, line2, file2_eof);

IF (file1_eof AND file2_eof) THEN

RETURN (TRUE);

ELSIF (line1 != line2) THEN

RETURN (FALSE);

ELSIF (file1_eof OR file2_eof) THEN

RETURN ( FALSE);

END IF;

END LOOP;

Aquí existen muchas salidas, por lo que esto se puede reemplazar por lo siguiente:

...

LOOP

read_line (file1, line1, file1_eof);

read_line (file2, line2, file2_eof);

IF (file1_eof AND file2_eof) THEN

retval := TRUE;

exit_loop := TRUE;

ELSIF (line1 != line2) THEN

retval := FALSE;

exit_loop := TRUE;

ELSIF (file1_eof OR file2_eof) THEN

retval := FALSE;

exit_loop := TRUE;

END IF;

EXIT WHEN exit_loop;

END LOOP;

RETURN (retval);

En este caso se contemplan las condiciones en muchos puntos, pero se evalúa la salida solo en un lugar para después realizar el RETURN.

•Nunca declarar el índice de un FOR ..LOOP.

PL/SQL ofrece dos tipos de FOR LOOP: Numéricos y cursores.

Ambos tienen este formato general:

FOR indice_loop IN loop range LOOP

Loop body

END LOOP;

El índice del loop se declara implícitamente durante la ejecución. El ámbito de existencia está restringido al cuerpo del loop.

Si se declarase el índice, se estaría generando otra variable completamente separada que en el mejor de los casos nunca será usada, pero si se usa fuera del loop, puede introducir errores.

Ejemplo

DECLARE CURSOR c_cuenta IS

SELECT nro_cuenta

FROM cuentas;

r_cuenta cuentas%ROWTYPE;

BEGIN

FOR r_cuenta in c_cuenta LOOP

Calcula_saldo(r_cuenta.nro_cuenta);

END LOOP;

DBMS_OUTPUT.PUT_LINE(r_cuenta.nro_cuenta);

END;

La línea que se encuentra fuera del loop, retorna nulo, ya que está fuera del alcance del mismo.

La línea que se encuentra fuera del loop, retorna nulo, ya que está fuera del mismo.

•Al utilizar la cláusula ELSIF, asegurarse que las condiciones son excluyentes

En el caso de sentencias que deban ingresar en un condicional si o si, se debe lanzar una excepción en caso de que esto no ocurra y no presuponer que nunca se cumplirá la condición.

Ejemplo:

DECLARE

IF SEXO = ‘M’ THEN

<>

ELSIF SEXO = ‘F’ THEN

•Reemplazar y simplificar el IF con variables booleanas.

Ejemplo

DECLARE

l_logicaBOOLEAN;

BEGIN

IF l_logica = TRUE THEN

ELSIF l_logica = FALSE THEN

END IF;

END;

Reemplazar por

DECLARE

l_logica BOOLEAN;

BEGIN

IF l_logica THEN

ELSIF NOT l_logica THEN

END IF;

END;

Pautas para el manejo de excepciones

Aunque se escriba un código perfecto, que no contenga errores y que nunca realice operaciones inapropiadas, el usuario podría usar el programa incorrectamente, produciendo una falla que no estaba contemplada. El uso de excepciones permite capturar y administrar los errores que se pueden producir dentro del código. Su buen uso trae como resultado un código con menos bugs y más fácil de corregir.

Establecer los lineamientos para el manejo de errores antes de comenzar a codificar.

Es impráctico definir secciones de excepciones en el código después de que el programa fue escrito.

La mejor forma de implementar un manejo de errores en toda la aplicación es usando paquetes que contengan al menos los siguientes elementos.

Procedimientos que realicen el manejo de tareas de excepciones, como por ejemplo escribir un log de errores.

Un programa que oculte la complejidad de RAISE_APPLICATION_ERROR y los números de application-error.

Una función que retorne el mensaje de error para un código de error.

Utilizar el modelo por defecto de manejo de excepciones para propagar la comunicación de errores.

Aprovechar la arquitectura de manejo de errores de PL/SQL y separar las excepcionesen bloques.

Evitar este tipo de código.

BEGIN

pkg_cuenta.determinar_estado (l_cuenta, error_code, error_msg);

IF error_code != 0 THEN

err.log (...);

GOTO end_of_program;

END IF;

pkg_cuenta.imprimir_estado (l_cuenta, error_code, error_msg);

IF error_code != 0 THEN

err.log (...);

GOTO end_of_program;

END IF;

END;

La sección de código ejecutable debe estar limpia, simple y fácil de seguir. No es necesario controlar el estado después de cada llamada a un programa. Simplemente debe incluirse una sección de excepción, capturar el error y determinar la acción a realizar.

•Capturar todas las excepciones y convertir el significado de los códigos de error en los retornos a programas que no son PL/SQL.

Cuando los programas PL/SQL son llamados por otros lenguajes de programación (Java, Visual Basic, etc), al menos es necesario regresar el estado de error (código y mensaje) para que administren los mismos.

Una manera sencilla de hacer esto es sobrecargar el programa original con otro del mismo nombre y dos parámetros adicionales.

Ejemplo

CREATE OR REPLACE PACKAGE pkg_cta_control

IS

PROCEDURE estado ( p_cuenta IN cuentas.nro_cuenta%TYPE);

PROCEDURE estado (

p_cuenta IN cuentas.nro_cuenta%TYPE,

error_code OUT INTEGER,

error_msg OUT VARCHAR2);

END pkg_cta_control;

Los desarrolladores pueden llamar al procedimiento que deseen y chequear los errores de la manera más apropiada para sus programas.

Usar procedimientos propios de RAISE en lugar de las llamadas explicitas a

RAISE_APPLICATION_ERROR.

Cuando se está controlando excepciones de sistemas como

NO_DATA_FOUND, se usa RAISE, pero cuando se quiere controlar un error de aplicación específico, se usa RAISE_APPLICATION_ERROR. Para el último caso, se debe asignar un número de error y mensaje, lo cual termina en un ‘hardcodeo’. Para ello se puede utilizar constantes para especificar un número. Una manera más clara es proveer un procedimiento que automáticamente controle el número de error y determina la forma de ejecutar el error.

Ejemplo

RAISE_APPLICATION_ERROR ( -20734, 'Sueldo menor al mínimo');

Se podría escribir de la siguiente forma

err.raise (errnums.sueldo_muy_bajo);

Los desarrolladores no tienen que determinar cuál es el número de error que tienen que usar, solo pasan la constante que desean usar y dejan que la rutina determine cuál es el RAISE correspondiente.