Manual Pl SQL

38
MANUAL PL/SQL ORACLE Qué es el lenguaje PL/SQL y primeras explicaciones para saber cómo funciona este gestor PL/SQL. La unidad de trabajo en PL/SQL es el bloque, constituido por un conjunto de declaraciones, instrucciones y mecanismos de gestión de errores y excepciones. Bloques Con PL/SQL se pueden construir distintos tipos de programas: procedimientos, funciones y bloques anónimos, paquetes, etc. Todos ellos tienen en común una estructura básica denominada bloque. Un bloque tiene 3 zonas: Zona de declaraciones: donde se declaran objectos locales. Suele ir precedida por la cláusula declare (o is o as en los procedimientos y funciones). Un conjunto de instrucciones precedido por la cláusula BEGIN Zona de excepciones: es una zona opcional precedida por la cláusula EXCEPTION, donde se gestionan las excepciones. El formato genérico de un bloque es el siguiente: [ DECLARE <declaraciones>] BEGIN <instrucciones> [EXCEPTION <gestión de excepciones>] END; Las únicas cláusulas obligatorias son BEGIN y END Antes de hacer ningún bloque tenemos que ejecutar el siguiente comando en nuestra ventana de Sql *PLUS set serveroutput on; ejemplo de un bloque

Transcript of Manual Pl SQL

Page 1: Manual Pl SQL

MANUAL PL/SQL ORACLE

Qué es el lenguaje PL/SQL y primeras explicaciones para saber

cómo funciona este gestor PL/SQL.

La unidad de trabajo en PL/SQL es el bloque, constituido por un conjunto de declaraciones,

instrucciones y mecanismos de gestión de errores y excepciones.

Bloques

Con PL/SQL se pueden construir distintos tipos de programas: procedimientos, funciones y

bloques anónimos, paquetes, etc. Todos ellos tienen en común una estructura básica

denominada bloque.

Un bloque tiene 3 zonas:

Zona de declaraciones: donde se declaran objectos locales. Suele ir precedida por la

cláusula declare (o is o as en los procedimientos y funciones).

Un conjunto de instrucciones precedido por la cláusula BEGIN

Zona de excepciones: es una zona opcional precedida por la cláusula EXCEPTION, donde se

gestionan las excepciones.

El formato genérico de un bloque es el siguiente:

[ DECLARE

   <declaraciones>]

BEGIN

   <instrucciones>

[EXCEPTION

   <gestión de excepciones>]

END;

Las únicas cláusulas obligatorias son BEGIN y END

Antes de hacer ningún bloque tenemos que ejecutar el siguiente comando en nuestra

ventana de Sql *PLUS

set serveroutput on;

ejemplo de un bloque

Page 2: Manual Pl SQL

DECLARE

   v_num_empleados number(2);

BEGIN

   insert into depart values(99,'provisional',null);

   update emple set dept_no=99 where dept_no=20;

   v_num_empleados:=SQL%ROWCOUNT;

   delete from depart where dept_no=20

   DBMS_OUTPUT.PUT_LINE (v_num_empleados || 'Empleados cambiados a provisional');

Definición de datos compatibles con SQL

Este lenguaje suele tener unos tipos de datos compatibles con SQL para las columnas de las

tablas, pero además puede tener otros tipos de datos propios.

Para declarar los datos en un bloque tenemos que utilizar una sintaxis como esta:

DECLARE

   nombre_variable Tipo dato;

BEGIN

...

Un ejemplo seria este:

DECLARE

   precio NUMBER(8,2);

   suma    NUMBER(2)    DEFAULT 0;

   prenda CHAR(20)    NOT NULL   :='Camiseta';

   descripción VARCHAR2(15);

BEGIN

....

Una de las ventajas de PL/SQL es que nos permite declarar una variable del mismo tipo que

otra variable o que una columna de una tabla. Esto lo hacemos con el atributo %TYPE.

DECLARE

   nombre emple.nombre%TYPE;

Otra ventaja es que nos permite guardar el contenido de una fila entera de una tabla en una

variable. Esto lo hacemos con el atributo %ROWTYPE

Page 3: Manual Pl SQL

DECLARE

   mifila emple%ROWTYPE;

Con esto ya podemos trabajar con variables dentro de nuestro bloque. Ahora tenemos que

ver las estructuras de control que podemos manejar dentro de nuestros bloques.

Estructuras de control

Las estructuras de control son básicamente las mismas que podemos utilizar en cualquier

lenguaje de programación.

La vamos a dividir en estructuras de control alternativas (IF) y estructuras de control

repetitivas (WHILE, FOR, LOOP)

La estructura del IF seria la siguiente:

IF <condición> THEN

   instrucciones

ELSEIF <condición> THEN

   instrucciones

....

ELSE

   instrucciones

END IF;

La estructura del WHILE seria la siguiente:

WHILE <condición> LOOP

   instrucciones

END LOOP;

La estructura del FOR se escribiría así:

FOR <variable> IN <mínimo> <máximo> LOOP

   instrucciones

END LOOP

Si queremos que nos vaya contando al revés, es decir de 5 hasta 0 por ejemplo, la sintaxis

seria la siguiente:

Page 4: Manual Pl SQL

FOR <variable> IN REVERSE

   <final>.......<inicio> LOOP

      instrucciones

      .....

END LOOP;

Y la estructura del LOOP seria de esta forma:

LOOP

   instrucciones

   ....

   EXIT WHEN <condición>

      instrucciones

   ...

END LOOP;

Cursores implicitos

Es importante saber que en nuestros bloques PL/SQL es bastante práctico el uso de cursores.

En este lenguaje el resultado de una consulta no va directamente al terminal del usuario,

sino que se guarda en un área de memoria a la que se accede mediante los nombrados

cursores. Para realizar una consulta en PL/SQL tenemos que guardar el resultado en cursores.

Esto es muy sencillo y basta con meter un INTO en las consultas. Un ejemplo seria este:

select <columna/s> INTO <variable/s> from <tabla> [where]

select count(*) INTO vnum from ventas;

La variable que sigue al INTO recibe el valor de la columna. Por este motivo es importante

que el tipo de dato de la variable coincida con el tipo de dato de la columna.

Gestión de excepciones

Las excepciones sirven para tratar los errores y mensajes. Oracle tiene una serie de

excepciones que son las más frecuentes y con las que la mayoría de la gente trabaja.

Unas de las más usadas son:

NO_DATA_FOUND (cuando una orden tipo select no ha devuelto ningún valor)

TOO_MANY_ROWS (cuando una orden tipo select ha devuelto mas de una fila)

OTHERS THEN RAISE_APPLICATION_ERROR (para cualquier otro tipo de error desconocido)

Page 5: Manual Pl SQL

Un ejemplo seria el siguiente:

DECLARE

   vapellido varchar(10);

   voficio varchar(20);

BEGIN

   select apellido,oficio INTO vape,voficio from emple where emp=15;

   DBMS_OUTPUT.PUT_LINE (vape||: - || voficio);

EXCEPTION

   WHEN NO_DATA_FOUND THEN insert into temp values('No hay datos');

   WHEN TOO_MANY_ROWS THEN insert into temp values ('Demasiados datos');

   WHEN OTHER THEN RAISE_APPLICATION_ERROR(-2000,'Error en aplicación');

END;

Estructura modular

En PL/SQL podemos distinguir 3 tipos de programas o bloques.

Bloques anónimos: Son los que no tienen nombre y comienzan con el DECLARE, es decir los

que hemos ido viendo hasta ahora.

Procedimientos: Se trata del programa más utilizado en PL/SQL y su formato es el siguiente:

PROCEDURE <nombre_procedimiento>

   [(<lista de parámetros>)]

   IS

      [<declaraciones>]

   BEGIN

      <instrucciones>;

   [EXCEPTIONS

      <excepciones>;]

   END;

En el formato distinguimos dos partes claramente, la cabecera donde esta el nombre del

procedimiento y los parámetros y el cuerpo donde se situá un bloque anónimo.

Funciones: similares a los procedimientos pero con la función añadida de que pueden

devolver valores.

Si subís varias lineas y veis el ejemplo de control de excepciones, podéis ver que hemos

utilizado un atributo como DBMS_OUTPUT. Bien pues esto lo que nos permite es visualizar en

pantalla los resultados, tanto excepciones como mensajes. Lo utilizamos porque PL/SQL no

dispone de ordenes o sentencias que capturen datos introducidos por teclado, ni tampoco

para visualizar datos en pantalla.

Page 6: Manual Pl SQL

DBMS_OUTPUT.PUT_LINE nos permite visualizar en pantalla, pero para que funcione

correctamente tenemos que poner el SET SERVEROUTPUT a ON

Si queremos que un bloque nos pida algún dato tenemos que anteponer el símbolo & delante

de la variable, de esta forma cuando el bloque llegue a ese punto nos pedirá por pantalla el

valor.

Otra sentencia importante es la que nos permite visualizar los errores que hemos podido

tener al crear el bloque o procedimiento. Esta sentencia es: show errors

Podemos agregar comentarios a nuestros bloques anteponiendo al comentario “/*

<comentario> */”

Si queremos que el bloque anónimo se ejecute directamente cuando terminamos de crearlo

debemos poner el símbolo / que, ademas de guardar el bloque en el buffer, lo ejecuta.

También podemos guardar los bloques anónimos en ficheros para poderlos ejecutar

posteriormente. Para ello ejecutamos la siguiente sentencia:

save nombrefichero

Y para ejecutarlo primero tenemos que cargar el fichero en el buffer y para ello tenemos que

ejecutar la siguiente sentencia:

get nombrefichero

Una vez cargado el fichero ejecutamos el bloque con la sentencia run nombrefichero.

O podemos hacer los dos pasos con una sola sentencia: start nombrefichero

Sin embargo para los procedimientos es totalmente distinto ya que al tener nombre se

almacena automáticamente en la base de datos y para ejecutarlo tan solo tenemos que

realizar la siguiente operación:

execute nombre_procedimiento(parámetros);

En el siguiente capitulo revisaremos todo lo que hemos visto en la introducción del PL/SQL,

pero de una forma mas exhaustiva.

Bloques anónimos PL/SQL

Empezaremos con los bloques anónimos, caracterizados porque no tienen nombre y se

suelen crear y ejecutar desde PL/SQL.

Page 7: Manual Pl SQL

Todo bloque debe acabar en . para que sea almacenado en el buffer SQL. Una vez guardado

lo podemos ejecutar con la orden “run”. También podemos guardarlo en un fichero con la

siguiente orden:

save nombrefichero [replace]

El replace sólo lo pondremos si el fichero ya esta creado.

Para cargar y ejecutar este bloque anónimo guardado en fichero ejecutaremos la siguiente

orden:

start nombrefichero

El start lo podemos cambiar por la @ y nos funcionará igualmente.

Pero también podemos cargarlo sin ejecutarlo con la orden “get” y luego ejecutarlo

posteriormente con la orden “run”

Un ejemplo muy sencillo de bloque seria el que nos muestra en pantalla un nombre.

BEGIN

   DBMS_OUTPUT.PUT_LINE('nombre');

END;

.

Además en los bloques PL/SQL se pueden utilizar lo que llamamos variables de sustitución,

que nos pedirán datos por pantalla antes de ejecutar el bloque. Estas variables tienen que ir

antepuestas del & para que funcionen.

Un ejemplo seria un bloque que nos pide el DNI de un usuario y nos muestra su nombre.

DECLARE

   Vnom clientes.nombre%TYPE;

BEGIN

   select nombre into Vnom from clientes where NIF= '&V_nif';

   DBMS_OUTPUT.PUT_LINE (Vnom);

END;

.

Como veis es bastante sencillo, pero no tienen tanta funcionalidad como los procedimientos

o funciones.

Page 8: Manual Pl SQL

Procedimientos y funciones PL/SQL

Los procedimientos y funciones quedan almacenados en la base de datos a diferencia de los

bloques anónimos que se almacenaban en el buffer.

Nota: Al quedar los bloques anónimos almacenados en el buffer, a no ser que se guardasen en ficheros,

se perderían al limpiar el buffer, cosa que no ocurre con los procedimientos y funciones, que se

almacenan en la propia base de datos.

Otra cosa que nos diferencia los bloques anónimos de los procedimientos o funciones es que

en los procedimientos o funciones no se pueden utilizar variables de sustitución.

En cuanto a su construcción es la dada en el articulo Características de PL/SQL segunda parte

añadiendo al principio la siguiente secuencia “CREATE OR REPLACE” para crearlo, o

modificarlo si ya existe.

Pasamos a escribir un procedimiento que nos muestre los datos de un usuario:

CREATE OR REPLACE PROCEDURE ver_usuario(nomusu VARCHAR2)

IS

   NIFusu   VARCHAR2(10);

   Domusu   VARCHAR2(10);

BEGIN

   select nif, domicilio into NIFusu,Domusu from usuario where nombre=nomusu;

   DBMS_OUTPUT.PUT_LINE('Nombre:'||nomusu|| 'NIF:' ||NIFusu|| 'Domicilio' ||Domusu);

EXCEPTION

   WHEN NO_DATA_FOUND THEN

      DBMS_OUTPUT.PUT_LINE('No hemos encontrado al usuario || nomusu);

END;

/

Si el compilador detecta errores nos saldrá un mensaje como este: “Procedimiento creado

con errores de compilación”. Para ver estos errores tenemos la orden SHOW ERRORS.

Al tener almacenado el procedimiento en la base de datos, este puede ser llamado por

cualquier usuario que tenga los permisos oportunos. Para invocar un procedimiento

utilizamos la orden EXECUTE

Para invocar al procedimiento que hemos creado antes tendríamos que ejecutar la siguiente

orden:

Page 9: Manual Pl SQL

EXECUTE ver_usuario('Luis');

Pero también podemos invocarlo desde un bloque PL/SQL de ls siguiente forma:

BEGIN

   ver_usuario('Luis');

END;

.

Como en cualquier lenguaje, podemos agregar comentarios a nuestros procedimientos de la

siguiente forma:

- - para comentar en una sola linea

/* <comentario>*/ para varias lineas.

Tipos de datos

Este lenguaje dispone de los mismo tipos de datos que podemos encontrar en SQL, pero

además se han incorporado algunos nuevos:

char(n): almacena una cantidad fija de caracteres

varchar2(n): almacena cadenas de caracteres de longitudes variables

long(n): almacena cadenas de longitud variable

number(p,e): almacena numero de precisión p y escala e

boolean: almacena valores lógicos, true, false o NULL

date: almacena fechas completas, incluida la hora

raw(n): almacena datos binarios de longitud fija

long raw : almacena datos binarios de longitud variable

rowid: almacena identificadores de direcciones de fila

etc.

Además es importante señalar que el programador puede definir sus propios tipos de datos a

partir de los ya definidos.

Identificadores

Se utilizan para nombrar los objetos que intervienen en los programas PL/SQL como son las

variables, constantes, cursores, excepciones, procedimientos, etc.

Page 10: Manual Pl SQL

Pueden tener como máximo 30 caracteres empezando siempre por una letra, que puede ir

seguida por otras letras, numeros, $, # ó _. Es importante destacar que PL/SQL no diferencia

entre mayúsculas y minúsculas. También debemos señalar que no pueden contener espacios

ni signos de puntuación.

Variables

Como doy por sentado que todos sabemos lo que son las variables, pasaremos directamente

a comentar como se declara una variable en PL/SQL.

<nombreVariable> <tipo> [NOT NULL] [{:= | DEFAULT } <valor>]

No podemos indicar una lista de variables del mismo tipo y luego declarar el tipo, tenemos

que hacerlo una a una.

Uno ejemplo de declaración de variables seria el siguiente:

DECLARE   

   importe NUMBER (8,2);

   contador NUMBER(2'0);

   nombre char(5) NOT NULL :="Sara";

...

Uso de los atributos %TYPE y %ROWTYPE

%TYPE: declara una variable del mismo tipo que otra, o que una columna de una tabla

%ROWTYPE : crea una variable registro cuyos campos se corresponden con las columnas de

una tabla o vista.

Por ejemplo si tenemos una variable definida previamente llamada cantidad podemos definir

otra de la siguiente forma:

   total cantidad%TYPE;

De esta forma la variable total tendrá las mismas características que la variable cantidad.

Otro ejemplo seria declarar una variable que fuera del mismo tipo que la columna nombre de

la tabla profesor.

   nombre_alta nombre%ROWTYPE;

Ámbito y visibilidad de variables

Page 11: Manual Pl SQL

La variable será local para el bloque en el que ha sido declarada y global para los bloque

hijos de éste, mientras que las variables declaradas en los bloque hijos no son globales a los

bloques padre.

Constantes

Cómo en la mayoría de los lenguajes, en este también podemos declaras constantes, de la

siguiente forma:

<nombreVariable> CONSTANT <tipo> := <valor>;

Operadores

Asignación :=

LógicosANDOR

NOTConcatenación ||

Comparación

Is null = != <> < >

<= >=

between...and like in

y sus correspondientes negacionesAritméticos + - * / **

Funciones predefinidas

En PL/SQL tenemos las mismas funciones predefinidas que en SQL (AVG, MIN, MAX, COUNT,

SUM, etc), pero tenemos que tener dos cosas muy claras a la hora de utilizarlas y son:

1. La función no modifica el valor de las variables o expresiones que se pasan como

argumentos, sino que devuelve un valor a partir de dicho argumento.

Page 12: Manual Pl SQL

2. Si a una función se le pasa un valor nulo en la llamada, posiblemente devolverá un

valor nulo.

Etiquetas

Podemos utilizar etiquetas para poder irnos a cualquier parte del programa utilizando la

sentencia GOTO siempre y cuando se cumplan las siguientes reglas:

1. No pueden haber etiquetas con los mismos nombres en un mismo programa.

2. La etiqueta debe preceder a un bloque o a un conjunto de ordenes ejecutables

3. La etiqueta no puede estar dentro de estructuras de control (IF, LOOP)

En cualquier subprograma podemos distinguir:

La cabecera, compuesta por el nombre del subprograma, los parámetros y el tipo de

valor de retorno.

El cuerpo, compuesto por las declaraciones, las instrucciones y el manejo de

excepciones.

Podemos distinguir entre dos tipos de subprogramas, como ya hemos comentado en artículos

anteriores:

Procedimientos

Los procedimientos ya los hemos visto en el articulo “Bloques anónimos y procedimientos

PL/SQL ” por lo que pasamos directamente a las funciones.

Funciones

Las funciones son muy similares a los procedimiento con la diferencia que éstas siempre

devolverán un valor. Su estructura es la siguiente:

CREATE [OR REPLACE] FUNCTION NombreFuncion [(parámetros)] RETURN tipo

IS [parte declarativa]

BEGIN   

   instrucciones

   RETURN <valor o expresión>;

[EXCEPTION excepciones]

END;

Page 13: Manual Pl SQL

La cláusula RETURN de la cabecera nos especifica el tipo de valor que nos va a devolver la

función.

Parámetros

Todos los subprogramas utilizan parámetros para pasar y recibir información.

Dentro de los parámetros podemos distinguir dos tipos:

Parámetros actuales: son variables indicadas en la llamada a un subprograma.

Parámetros formales: son variables declaradas en la especificación del subprograma.

Además podemos hacer el paso de parámetros de un tipo a otro. Generalmente si los tipos

son compatibles PL/SQL lo hace automáticamente. En cualquier caso, podemos hacerlo de

forma manual utilizando las siguientes notaciones:

Posicional: el compilador asocia los parámetros actuales a los formales, basándose

en suposición.

Nominal: el símbolo => después del parámetro actual y antes del nombre del formal,

indica al compilador correspondencia.

Mixta: nos permite usar las dos notaciones anteriores.

Para que esto quede más claro pasamos a escribir un ejemplo de paso de parámetros y

conversión de tipos.

Tenemos la especificación de un procedimiento como esta:

   PROCEDURE departamento(

      n_departamento INTEGER,

      localidad VARCHAR2

   IS...

Desde el siguiente bloque se podrán realizar las llamadas indicadas:

   DECLARE

      num_departamento INTEGER;

      aula VARCHAR(30)

   BEGIN

   ...

    - - posicional departamento(num_departamento, aula);

Page 14: Manual Pl SQL

    - - nominal departamento(num_departamento => n_departamento, aula =>localidad);

   ...

   END;

Esto nos pasaría los parámetros num_departamento al mismo tipo que n_departamento y

localidad al mismo tipo que aula.

Los parámetros que soporta PL/SQL pueden ser de entrada, salida o entrada/salida

IN

Nos permite pasar valores a un subprograma. Dentro del subprograma, el parámetro actuá como una

constante. Puede ser una variable, constante, literal o expresión.

OUT

Permite devolver valores al bloque que llamó al subprograma. Dentro del subprograma, el parámetro

actúa como una variable no inicializada. Solo puede ser una variable.

IN OUT

Permite pasar un valor inicial y devolver un valor actualizado. Dentro del subprograma, el parámetro

actuá como variable inicializada. Puede intervenir otras expresiones. El valor actual debe ser una variable.

El formato genérico es el siguiente:

<nombrevariable> [IN | OUT | IN OUT] <tipodato>

         [ { := | DEFAULT} <valor>]

Además es importante recordar que al especificar parámetros debemos indicar el tipo, pero

no el tamaño.

Creación, modificación y borrado de subprogramas

Cuando creamos subprogramas con SQL * PLUS utilizando los comandos CREATE, Oracle

automáticamente compila el código fuente, genera el código objeto y los guarda en el

diccionario de datos, quedando disponibles para su utilización.

Para volver a compilar un subprograma almacenado utilizaremos la orden ALTER en vez del

CREATE y su formato es el siguiente:

Page 15: Manual Pl SQL

   ALTER {PROCEDURE | FUNCITON} nombresubprograma COMPILE;

Para ver el código de un subprograma almacenado podemos ejecutar una sentencia como

esta;

   select LINE, SUBSTR(TEXT,1,60) from USER_SOURCE where name = 'nombresubprograma';

Para borrar un subprograma almacenado utilizaremos la orden DROP de la siguiente forma:

   DROP {PROCEDURE | FUNCTION} nombresubprograma;

Nota: PL/SQL implementa la recursividad en los subprogramas, esto quiere decir, que un programa

puede llamarse a si mismo.

En los anteriores capítulos hemos visto los fundamentos del lenguaje PL/SQL, bien pues, a

partir de ahora pasaremos a estudiar el manejo de este lenguaje para trabar con el gestor de

Oracle. Empezaremos con la utilización de cursores.

Hasta ahora hemos utilizado cursores implícitos , cuando devolvíamos el resultado de una

select mediante la clausula into a una variable. Pero esto es un problema cuando el resultado

de una subconsulta nos devolvía varias filas, porque esto nos daria un error al ejecutar la

consulta

Para que no nos salte un error en estos casos debemos utilizar los cursores explícitos.

Cursores explícitos

Los cursores explícitos los utilizamos cuando tenemos consultas que nos devuelven

más de una fila.

Tenemos 4 operaciones básicas para trabajar con un cursor explícito.

1. Declaración del cursor: lo tenemos que declarar en la zona de declaraciones, con el

siguiente formato: CURSOR <nombrecursor> IS <sentencia SELECT>;

2. Apertura del cursor: Deberá colocarse en la zona de instrucciones, con el siguiente

formato:

OPEN <nombrecursor>;

Al hacerlo se ejecuta automáticamente la sentencia select y sus resultados se

almacenan en las estructuras internas de memoria manejadas por el cursor.

3. Recogida de información: Para recuperar la información anteriormente guardada en

las estructuras de memoria interna tenemos que usar el siguiente formato:

Page 16: Manual Pl SQL

FETCH <nombrecursor> INTO {<variable> | <listavariables>};

Si tenemos una única variable que recoge los datos de todas las columnas, el

formato de la variable seria el siguiente:

<variable> <nombrecursor>%ROWTYPE;

Si tenemos una lista de variables, cada una recogerá la columna correspondiente de

la cláusula select, por lo que serán del mismo tipo que las columnas.

4. - Cierre del cursor:

CLOSE <nombrecursor>;

Ahora, veamos un ejemplo de utilización de cursores explícitos:

DECLARE   

   CURSOR C1 IS SELECT nombre, apellido FROM arbitro;

   Vnom VARCHAR2(12);

   Vape    VARCHAR2(20);

BEGIN

   OPEN C1;

   LOOP

      FETCH C1 INTO Vnom, Vape;

      EXIT WHEN C1%NOTFOUND;

      DBMS_OUTPUT.PUT_LINE(Vnom || '' || Vapen);

   END LOOP;

   CLOSE C1;

END;

Si nos fijamos, en la declaración de los cursores explícitos no utilizamos la cláusula INTO, que

sí se utilizaba en los cursores implícitos.

Además podéis ver que después del FETCH hemos comprobado si nos devuelve valores con

la línea del EXIT. Es algo importante ya que si no nos devuelve nada el LOOP se interrumpirá.

Atributos del cursor

Para conocer detalles de la situación del cursor tenemos 4 atributos:

%FOUND: devuelve verdadero si el último FETCH ha recuperado algún valor; en caso

contrario devuelve falso; si el cursor no está abierto nos devuelve error.

%NOTFOUND: hace justamente lo contrario al anterior.

%ROWCOUNT: nos devuelve el número de filas recuperadas hasta el momento.

%ISOPEN: devuelve verdadero si el cursor está abierto.

Page 17: Manual Pl SQL

Veamos ahora un ejemplo de utilización de %ROWCOUNT:

DECLARE

      CURSOR C1 IS SELECT nombre from futbolista WHERE Cod='e1';

      Vnom VARCHAR2(15);

   BEGIN

      OPEN C1;

      LOOP

         FETCH C1 INTO Vnom;

         EXIT WHEN C1%NOTFOUND;         

         DBMS_OUTPUT.PUT_LINE (C1%ROWCOUNT || Vnom);

         

      END LOOP;

      CLOSE C1;

   END;

Variables de acoplamientos en el manejo de cursores

En el ejemplo siguiente podemos observar que en la cláusula WHERE se incluye una variable

que se debería haber declarado previamente. Este tipo de variables reciben el nombre de

variables de acoplamiento. El programa la sustituirá por su valor en el momento en que se

abre el cursor, y se seleccionarán las filas según dicho valor. Aunque ese valor cambie

durante la recuperación de los datos con FETCH, el conjunto de filas que contiene el cursor

no variará.

El ejemplo nos muestra los futbolistas de un equipo cualquiera.

CREATE OR REPLACE PROCEDURE ver_futbolistas_por_equipos(codeq VARCHAR2)

IS

   Vequi VARCHAR2(3);

   CURSOR C1 IS SELECT nombre from futbolista where codeq=Vequi;

   Vnom VARCHAR(15);

BEGIN

   vequi:=codeq;

   OPEN C1;

   FETCH C1 INTO vnom;

   WHILE C1%FOUND LOOP

      DBMS_OUTPUT.PUT_LINE(Vnom);

      FETCH C1 INTO Vnom;

   END LOOP;

Page 18: Manual Pl SQL

   CLOSE C1;

END;

Variables de acoplamiento

Si os fijáis en el siguiente ejemplo veréis que en la cláusula where se incluye una variable

que se deberá declarar previamente. Este tipo de variables recibe el nombre de variables de

acoplamiento. El programa la sustituirá por su valor en el momento en que se abre el cursor,

y se seleccionarán las filas según dicho valor.

Create or replace procedure ver_jugador(codeq varchar2)

IS

   vequi varchar2(3);

   cursor c1 is select nombre from jugador where cod=vequi;

   vnom varchar2(15);

BEGIN

   vequi:=codeq;

   OPEN c1;

   FETCH c1 INTO vnom;

   WHILE c1%found LOOP

      DBMS_OUTPUT.PUT_LINE(vnom);

      FETCH c1 INTO vnom;

   END LOOP;

   CLOSE c1;

END;

Cursor FOR …. LOOP

El trabajo normal de un cursor consiste en declarar un cursor, declarar una variable que

recogerá los datos del cursor, abrir el cursor, recuperar con fetch, una a una, las filas

extraídas introduciendo los datos en las variables, procesándolos y comprobando si se han

recuperado datos o no.

Para resumir todas esas tareas, tenemos una estructura cursor FOR...LOOP que hace todas

estas cosas de forma implícita, todas menos la declaración del cursor.

El formato y el uso de esta estructura es:

1. se declara la información cursor en la sección correspondiente

Page 19: Manual Pl SQL

2. Se presenta el cursor utilizando el siguiente formato: FOR nombreVarReg IN

nombreCursor

LOOP …. END LOOP;

Al entrar en el bucle se abre el cursor de manera automática, se declara

implícitamente la variable nombreVarReg de tipo nombrecursor%ROWTYPE y se

ejecuta el primer fetch cuyo resultado quedarán en nombreVarReg. A continuación se

realizaran las acciones que correspondas hasta llegar al END LOOP.

Este es un ejemplo del LOOP …. END LOOP:

DECLARE

   cursor c2 is select nombre, peso, estatura from jugador where salario>1200;

BEGIN

   FOR vreg IN c2 LOOP

      DBMS_OUTPUT.PUT_LINE (vreg.nombre || '-' ||vreg.peso || '-' || vreg.estatura);

   END LOOP;

END;

Cursores con parámetros

Un cursor puede tener parámetros; en este caso se aplicara el siguiente formato genérico:

   CURSOR nombrecursor [(parámetros)] IS SELECT <sentencia select en la que intervendrán

los parámetros>;

Los parámetros formales indicados después del nombre del cursor tienen la siguiente

sintaxis:

nombreCursor [IN] tipodato [{:=|DEFAULT} valor]

Todos los parámetros formales de un cursor son parámetros de entrada y su ámbito es local

al cursor por eso sólo pueden ser referenciados dentro de la consulta.

Un ejemplo seria el siguiente:

DECLARE

...

CURSOR C1 (vpeso number, vestatura number DEFAULT 170) is select nficha, nombre FROM

emple WHERE estatura=vestatura AND peso=vpeso;

Page 20: Manual Pl SQL

Para abrir un cursor con parámetros lo haremos de la siguiente forma:

   OPEN nombrecursor [(parámetros)];

Atributos con Cursores implícitos

Los atributos de los cursores implícitos que se crean son los siguientes:

SQL%NOTFOUND: nos dice si el último insert, update,delete o select into no han

afectado a ninguna fila.

SQL%FOUND: nos dice si el último insert, update,delete o select into ha afectado a

una o mas filas

SQL%ROWCOUNT: devuelve el número de filas afectadas por el último insert, update,

delete o select into

SQL%ISOPEN: Nos dice si el cursor esta cerrado, por lo que en teoría siempre nos

dará falso ya que Oracle cierra automáticamente el cursor después de cada orden

SQL.

Es importante tener en cuenta una serie de cosas:

Si se trata de un select into tenemos que tener en cuenta que solo puede devolver una única

fila de lo contrario nos levantará automáticamente una de estas dos excepciones:

NO_DATA_FOUND: si la consulta no devuelve ninguna fila

TOO_MANY_ROWS: si la consulta devuelve más de una fila

Cuando un select into hace referencia a una función de grupo nuca se levantará la excepción

NO_DATA_FOUND y SQL%FOUND siempre será verdadero. Esto se explica porque las

funciones de grupo siempre devuelven algún valor (NULL se considera un valor).

Uso de cursores para actualizar filas

Para realizar una actualización con un cursor tenemos que añadir la siguiente FOR UPDATE al

final de la declaración del cursor:

CURSOR nombre_cursor <declaraciones> FOR UPDATE

Esto indica que las filas seleccionadas por el cursor van a ser actualizadas o borradas. Una

vez declarado un cursor FOR UPDATE, se incluirá el especificador CURRENT OF

Page 21: Manual Pl SQL

nombre_cursor en la cláusula WHERE para actualizar o borrar la última fila recuperada

mediante la orden FETCH.

{UPDATE|DELETE}... WHERE CURRENT OF nombre_cursor.

Os pongo un ejemplo para que quede claro:

Subir el salario a todos los empleados del departamento indicado en la llamada. El porcentaje

se indicará también en la llamada.

CREATE OR REPLACE PROCEDURE subir_salario (num_dept NUMBER, incre NUMBER)

IS

   CURSOR c IS SELECT oficio, salario FROM empleados WHERE    cod_dept=num_dept

   FOR UPDATE;

   reg c%ROWTYPE;

   inc NUMBER (8);

BEGIN

   OPEN c;

   FETCH c INTO reg;

   WHILE c%FOUND LOOP

         inc :=(reg.salario/100 )* inc;

         UPDATE empleados SET salario=salario+inc WHERE CURRENT          OF c

         FETCH c INTO reg;

   END LOOP;

END;

También podemos usar ROWID en lugar de FOR UPDATE. ROWID nos indicará la fila que se va

a actualizar. Para ello, al declarar el cursor en la cláusula SELECT indicaremos que seleccione

también el identificador de fila:

CURSOR nombre_cursor IS SELECT columna1,columna2,...ROWID FROM tabla;

Al ejecutarse el FETCH se guardará el número de fila en una variable y después ese número

se podrá usar en la cláusula WHERE de la actualización:

{UPDATE |DELETE } ... WHERE ROWID = variable_rowid

El ejemplo anterior utilizando ROWID quedaría de la siguiente manera:

CREATE OR REPLACE PROCEDURE subir_salario (num_dept NUMBER, incre NUMBER)

IS

Page 22: Manual Pl SQL

   CURSOR c IS SELECT oficio, salario,ROWID FROM empleados WHERE    cod_dept=num_dept

   FOR UPDATE;

   reg c%ROWTYPE;

   inc NUMBER (8);

BEGIN

   OPEN c;

   FETCH c INTO reg;

   WHILE c%FOUND LOOP

         inc :=(reg.salario/100 )* inc;

         UPDATE empleados SET salario=salario+inc WHERE ROWID =

reg.ROWID;         

         FETCH c INTO reg;

   END LOOP;

END;

En este artículo del Manual de PL/SQL de Oracle vamos a ver lo que son las excepciones,

para qué sirven y cómo utilizarlas. Daremos un repaso también a los tipos de excepciones,

las excepciones definidas por el usuario y la sintaxis con la que tenemos que especificarlas.

Por último, de paso que vemos cosas acerca del tratamiento de errores en PL/SQL,

explicaremos el RAISE_APPLICATION_ERROR, un componente del sistema gestor de base de

datos Oracle que ayuda a gestionar errores y sus mensajes de error.

Qué son las excepciones en Oracle

Las excepciones, presentes en la mayoría de los lenguajes de programación, sirven para

tratar errores en tiempo de ejecución. En el sistema que nos ocupa, Oracle, sirven también

para definir qué se debe hacer frente a errores en sentencias definidas por el usuario.

Cuando se produce un error PL/SQL levanta una excepción y pasa el control a la sección

excepción correspondiente al bloque PL/SQL.

El formato sería el siguiente:

BEGIN

   .........

   ......

   ......

EXCEPTION

Page 23: Manual Pl SQL

   WHEN <nombre_excepción> THEN

      <instrucciones>;

   ......

   [WHEN OTHERS THEN <instrucciones>;]

END;

Excepciones predefinidas

Son aquellas que se disparan automáticamente al producirse determinados errores. Estas

son las más comunes:

too_many_rows: Se produce cuando select … into devuelve más de una fila.

no_data_found: se produce cuando un select …. into no devuelve ninguna fila.

login_denied: error cuando intentamos conectarnos a Oracle con un login y clave no

validos.

not_logged_on: se produce cuando intentamos acceder a la base de datos sin estar

conectados.

program_error: se produce cuando hay un problema interno en la ejecución del programa.

value_error: se produce cuando hay un error aritmético o de conversión.

zero_divide: se puede cuando hay una división entre 0.

dupval_on_index: se crea cuando se intenta almacenar un valor que crearía duplicados en

la clave primaria o en una columna con restricción UNIQUE.

invalid_number: se produce cuando se intenta convertir una cadena a un valor numérico.

Hay alguna más pero estas son las más utilizadas y tenemos que tener en cuenta que no es

necesario declararlas en la sección DECLARE.

Excepciones definidas por el usuario

Son aquellas que crea el usuario. Para ello se requieren tres pasos:

1. Definición: se realiza en la zona de DECLARE con el siguiente formato:

nombre_excepción EXCEPTION

2. Disparar o levantar la excepción mediante la orden raise: RAISE ;

3. Tratar la excepción en el apartado EXCEPTION: WHEN THEN ;

Para que esto quede más claro ponemos un ejemplo a continuación.

Page 24: Manual Pl SQL

DECLARE

...

Importe_mal EXCEPTION;

...

BEGIN

...

IF precio NOT BETWEEN mínimo and máximo THEN

   RAISE importe_mal;

END IF;

...

EXCEPTION

   WHEN importe_mal THEN DBMS_OUTPUT.PUT_LINE("Importe incorrecto");

   ...

END;

Otras excepciones

Existen otros errores internos de Oracle que no tienen asignada una excepción, sino un

código de error y un mensaje, a los que se accede mediante funciones SQLCODE y SQLERRM.

Cuando se produce un error de estos se trasfiere directamente el control a la sección

EXCEPTION donde se tratara el error en la clausula WHEN OTHERS de la siguiente forma:

WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('Error'||SQLCODE||SQLERRM.)

Utilización de RAISE_APPLICATION_ERROR

En el paquete DBMS_STANDARD se incluye un procedimiento llamado

RAISE_APPLICATION_ERROR que nos sirve para levantar errores y definir mensajes de error.

Su formato es el siguiente:

RAISE_APPLICATION_ERROR(numero_error,mensaje_error);

Es importante saber que el número de error está comprendido entre -20000 y -20999 y el

mensaje es una cadena de caracteres de hasta 512 bytes.

Este procedimiento crea una excepción que solo puede ser tratada en WHEN OTHERS.

Ponemos un ejemplo para que nos quede más claro.

CREATE or REPLACE PROCEDURE subir_horas (emple NUMBER, horas_subir NUMBER)

IS

Page 25: Manual Pl SQL

   horas_actuales NUMBER;

BEGIN

   Select horas into horas_actuales from empleados where id_empleado=emple;

   if horas_actuales is NULL then

      RAISE_APPLICATION_ERROR(-20010,'No tiene horas');

   else

      update empleados set horas=horas_actuales + horas_subir where id_empleado=emple;

   end if;

End subir_horas;

Control de transacciones en Oracle. Una transacción se define como

un conjunto de operaciones sobre la base de datos.

En Oracle si se ejecuta un conjunto de operaciones y una de ellas falla se aborta la

transacción entera. En este artículo veremos todo lo que debemos saber sobre transacciones

y algunos ejemplos interesantes.

La transacción finaliza cuando se ejecuta un comando de control de transacciones como

rollback o commit work (se puede abreviar poniendo simplemente commit).

Un ejemplo:

BEGIN

....

update alumnos set edad=20 where n_alumno=109;

update nuevos set apellido='perez' where n_alumno=200;

commit work;

...

EXCEPTION

   WHEN OTHERS THEN

      rollback work;

END;

Comandos utilizados para el control de transacciones

Commit

Este comando da por concluida la transacción actual y hace definitivos los cambios

Page 26: Manual Pl SQL

realizados liberando las filas bloqueadas. Sólo después de que se ejecute commit tendremos

acceso a los datos modificados.

Rollback

Este comando da por concluida la transacción actual y deshace los cambios que se pudiesen

haber producido en la misma, liberando las filas bloqueadas. Se utiliza especialmente cuando

no se puede concluir una transacción porque se han levantado excepciones.

Savepoint

Se utiliza para poner marcas o puntos de salvaguarda al procesar transacciones. Se utiliza

junto con rollback permitiendo deshacer cambios hasta los savepoint.

El número de savepoint esta limitado a 5 por sesión pero lo podemos modificar con la

siguiente sentencia:

savepoint numero;

Rollback implicito

Este comando se ejecuta cuando un programa almacenado (procedimiento o función) falla y

no se controla la excepción que produjo el fallo. Pero si en el programa tenemos un commit

estos cambios no serán deshechos.

Rollback to

Deshace el trabajo realizado después del punto indicado. Pero no se confirma el trabajo

hecho hasta el savepoint. La transacción no finaliza hasta que se ejecuta un comando de

control de transacciones o hasta que finaliza la sesión.

Os dejo a continuación un ejemplo bastante completo de lo que sería el control de

transacciones:

create or replace procedure prueba (nfilas number)

as

   begin

      savepoint ninguna;

      insert into tmp values ('primera fila');

      savepoint una;

      insert into tmp values ('segunda fila');

      savepoint dos;

      if nfilas=1 then

         rollback to una;

      else if nfilas=2 then

Page 27: Manual Pl SQL

         rollback to dos;

      else

         rollback to ninguna;

      end if;

      commit;

      exception

         when other then

            rollback

end prueba;

Con este artículo terminamos la parte básica sobre oracle, PL/SQL y pasamos a lo que

podemos denominar programación avanzada de sql. Empezaremos con triggers en el

siguiente artículo.

En el presente artículo vamos a estudiar acerca de los triggers, donde veremos qué son y

cómo se construyen, comenzando con los trigger de tablas y más tarde veremos los trigger

de sustitución y los de sistema. Para ello lo primero que tenemos que ver es su definición.

Trigger a tablas

Un trigger es un bloque de código PL/SQL que se almacenan en la base de datos. Los bloques

de código de los triggers están asociados a una tabla y se ejecutan automáticamente cuando

se producen ciertos eventos asociados a la tabla.

Se suelen utilizar para prevenir transacciones erróneas y nos sirven también para

implementar restricciones de integridad o seguridad.

Su formato básico es el siguiente:

create or replace trigger nombre_trigger

   {before | after} {delete | insert | update[of lista_columnas]}

   [or {before | after} {delete|insert|update [of lista_columnas]}]

   on nombre_tabla

   [for each {row | statement | when (condición)}]

   /* comienza el trigger */

   [declare]

      <declaraciones>

   begin

      <instrucciones>

   [exception]

Page 28: Manual Pl SQL

      <excepciones>

end;

Elementos de un trigger

before / after: elemento que dispara el trigger

nombre: nombre del trigger que tiene que ser único.

for each: nivel del disparo del trigger que por defecto es statement que significa que se

dispara una sola vez por cada operación independientemente del número de filas afectadas.

for each row: salta por cada fila afectada.

Variables posibles para update: la primera es :old que hace referencia a los valores

anteriores y :new que hace referencia a los nuevos valores de actualización de la fila.

Tenemos que tener en cuanta unos cuantos aspectos:

Cuando el evento que dispara el trigger es un delete haremos referencia al valor :old

porque el valor :new es nulo

Cuando el evento que dispara el trigger es un insert haremos referencia al valor :new

porque el :old es nulo.

Cuando el evento es un update tiene sentido hacer referencia a los dos valores.

Sólo se pueden utilizar cuando el trigger es a nivel de fila (for each row).

Vamos a crear un trigger que se disparé automáticamente después de la modificación del

salario de la tabla empleado y pase un comentario a la tabla a auditar.

Create or replace trigger auditar_salario

      after update of salario

      on empleado

      for each row

   begin

insert into auditar values

         ('se ha modificado el salario' || :old.num_empleado);

   end;

Orden de ejecución de los trigger

Una misma tabla puede tener varios triggers y el orden de disparo sería el siguiente:

Page 29: Manual Pl SQL

1. Antes de comenzar a ejecutar la orden que provoca el disparo se ejecutaran los

triggers del tipo before.... for each statement

2. Para cada fila afectada por la orden:

a) se ejecutan los triggers del tipo before … for each row

b) se ejecuta la actualización de la fila

c) se ejecutan los triggers after... for each row

3. Una vez realizada la operación se ejecuta el after … for each statement

Cuanndo se dispara un trigger este forma parte de la operación que lo disparó de manera

que si el trigger falla, Oracle dará por fallida la operación completa. Aunque el fallo sea a

nivel de fila se hará rollback a toda la operación.

Ejemplo:

create or replace trigger nombre_trigger

   before insert or delete

begin

   if insert then

      .....

   elseif deleting then

      ....

   elseif updating then

      ...

   end if

   ....

end;

Disparadores de sustitución

Podemos crear triggers que no se ejecutan antes ni después de una instrucción sino en lugar

de (instead of).

Solo podemos utilizar estos triggers si están asociados a vistas, además actúan siempre a

nivel de fila.

La sintaxis de este tipo de trigger es la siguiente:

create [or replace] trigger nombre_trigger

   instead of { insert | delete | update [of columnas]}

   [ or { insert | delete | update}]

   on nombre vista

Page 30: Manual Pl SQL

   [ for each row]

   [declare]

      declaraciones

   begin

      instrucciones

   [execption]

      excepciones

   end;

Sobre una vista podemos hacer un select pero si hacemos un insert, delete o update puede

darnos problemas y no dejar ejecutarse la orden correctamente.

Los trigger sobre vistas vas a sustituir a estas operaciones por las correspondientes en las

tablas que forman la vista.

Un ejemplo de trigger de sustitución seria el siguiente:

create or replace trigger t_borrado_emp

   instead of delete on empleado

   for each row

begin

   delete from emple where emp_num=:old.cod

end;

Disparadores de sistema

Estos trigger se disparan cuando se arranca o para la base de datos, entra o sale un usuario,

cuando se crea, modifica o elimina un objeto, etc.

En Oracle para crear este tipo de trigger tenemos que tener privilegios de Administer

database trigger.

La sintaxis de este trigger seria la siguiente:

create [or replace] trigger nombre_trigger

   { before | after } { <lista eventos de definición> | <lista eventos del sistema>}

   on { database | schema} [when (condición)]

   <cuerpo del trigger (bloque PL/SQL)>

Donde la lista de eventos de definición puede tener uno o más eventos DDL separados por or

y la lista de eventos del sistema igualmente separados por or.

Page 31: Manual Pl SQL

Al asociar un disparador a un evento debemos indicar el momento en que se dispare. A

continuación os dejo una tabla de evento, momento y cuando se dispararía para dejarlo todo

mas o menos claro.

Evento Momento Se disparan:STARTUP AFTER Después de arrancar la instancia

SHUTDOWN BEFORE Antes de apagar la istancia

LOGON AFTERDespués de que el usuario se conecte a

la base de datos.LOGOFF BEFORE Antes de la desconexión de un usuario

SERVERERROR AFTER Cuando ocurre un error en el servidor

CREATEBEFORE |

AFTERAntes o después de crear un objeto en el

esquema

DROPBEFORE |

AFTERAntes o después de borrar un objeto en

el esquema

ALTERBEFORE |

AFTERAntes o después de cambiar un objeto

en el esquema

TRUNCATEBEFORE |

AFTERAntes o después de ejecutar un

comando truncate

GRANTBEFORE |

AFTERAntes o después de ejecutar un

comando grant

REVOKEBEFORE |

AFTERAntes o después de ejecutar un

comando revoke

DLLBEFORE |

AFTERAntes o después de ejecutar cualquier

comando de definición de datos

Oracle tiene algunas funciones que permiten acceder a los atributos del evento del disparo

ORA_YSEVENT, ORA_LOGIN, etc. Estas funciones pueden usarse en la clausula WHEN o en el

cuerpo del disparador. En el manual de Oracle podéis encontrar el listado de todas estas

funciones.

Un ejemplo seria un trigger que nos guarda los datos de un usuario al hacer login en la base

de datos:

create or replace trigger control

   after logon

   on database

   begin

      insert into control_conexion (usuario, momento, evento)

      values {ORA_LOGIN_USER, SYSTIMESTAMP, ORA_SYSEVENT);

   end;

Page 32: Manual Pl SQL

Vamos a ver que son los paquetes en el sistema gestor de base de

datos Oracle, explicando estructura y funcionamiento.

Por Sara AlvarezAtención: Contenido exclusivo de DesarrolloWeb.com. No reproducir. Copyright.

En este artículo que pertenece al tutorial de Oracle trateremos el tema de los paquetes de

forma detenida.

Los paquetes en Oracle se utilizan para guardar subprogramas y otros objetos de la base de

datos.

Un paquete consta de los siguientes elementos:

Especificación o cabecera: contiene las declaraciones públicas (es decir, accesibles

desde cualquier parte de la aplicación) de sus programas, tipos, constantes,

variables, cursores, excepciones, etc.

Cuerpo: contiene los detalles de implementación y declaraciones privadas, es decir,

accesibles solamente desde los objetos del paquete.

La sintaxis de la cabecera es la siguiente:

   create [or replace] package nombre_paquete as

      <declaraciones públicas>

      <especificaciones de subprogramas>

   end nombre_paquete;

La sintaxis del cuerpo sería la siguiente:

   create [or replace] package body nombre_paquete as

      <declaraciones privadas>

      <código de subprogramas>

      [begin

         <instrucciones iniciales>]

   end nombre_paquete;

Como podéis observar la cabecera se compila independientemente del cuerpo. Os dejo un

ejemplo de paquete para que lo veáis más claro.

/* Cabecera */

create or replace package busar_emple as

   TYPE t_reg_emple is RECORD

Page 33: Manual Pl SQL

      (num_empleado emple.emp_no%TYPE,

      apellido emple.apellido%TYPE,

      salario emple.salario%TYPE,

      departamento emple.dept_no%TYPE);

   procedure ver_por_numero(v_cod emple.emp_no%TYPE);

   procedure ver_por_apellido(v_ape emple.apellido%TYPE);

   function datos (v_cod emple.emp_no%TYPE)

      return t_reg_emple;

end buscar_emple;

/* Cuerpo */

create or replace package body buscar_emple as

   vg_emple t_reg_emple;

   procedure ver_emple; /* procedimiento privado*/

   procedure ver_por_numero (v_cod emple.emp_no%TYPE)

   is

   begin

      select emp_no, apellido, salario, dept_no into vg_emple from emple where

emp_no=v_cod;

      ver_emple;

   end ver_por_numero;

   procedure ver_por_apellido (v_ape emple.apellido%TYPE)

   is

   begin

      select emp_no,apellido,salario,dept_no into vg_emple from emple where

apellido=v_apellido;

      ver_emple;

   end ver_por_apellido;

   function datos (v_cod emple.emp_no%TYPE)

      return t_reg_emple

   is

   begin

      select emp_no,apellido,salario,dept_no into vg_emple from emple where

emp_no=v_cod;

   procedure ver_emple

      is

      begin

Page 34: Manual Pl SQL

         DBMS_OUTPUT.PUT_LINE(vg_emple.num_empleado || '*' || vg_emple.apellido || '*'

|| vg_emple.salario || '*'|| vg_emple.departamento);

   end ver_emple;

end buscar_emple;

Como podéis ver este paquete nos permite buscar un empleado de tres formas distintas y

visualizar sus datos.

Utilización de los objetos definidos en los paquetes

Podemos utilizar los objetos definidos en los paquetes básicamente de dos maneras distintas:

Desde el mismo paquete: esto quiere decir que cualquier objeto puede ser utilizado

dentro del paquete por otro objeto declarado en el mismo.

Para utilizar un objeto dentro del paquete tan sólo tendríamos que llamarlo. La

llamada sería algo así: v_emple :=buscar_emple.datos(v_n_ape); (como veis no

utilizamos el execute ya que nos encontramos dentro del paquete).

Desde fuera del paquete: Podemos utilizar los objetos de un paquete siempre y

cuando haya sido declarado en la especificación del mismo. Para llamar a un objeto o

procedimiento desde fuera del paquete utilizaríamos la siguiente notación: execute

nombre_paquete.nombre_procedimiento(lista de parametros);

Declaración de cursores en paquetes

En los paquetes también podemos introducir cursores, para ello debemos declararlo en la

cabecera del paquete indicando su nombre, los parámetros y tipo devuelto. Para que lo veáis

más claro os dejo un ejemplo a continuación:

CREATE or REPLACE PACKAGE empleados AS

   .....

   CURSOR a RETURN empleado%ROWTYPE;

   ...

   END empleados;

CREATE or REPLACE PACKAGE BODY empleados AS

   ....

   CURSOR a RETURN empleado%ROWTYPE

      SELECT * FROM empleado WHERE salario < 10000;

   ....

END empleados;

Page 35: Manual Pl SQL

Los paquetes suministrados por Oracle son:

Standard : tiene la función to_char y abs

dbms_standard: tiene la función raise_aplication_error

dbms_output: con la función put_line

dbms_sql: que utiliza sql de forma dinámica.

NOTA: sql dinámico significa que el programa es capaz de ejecutar órdenes de definición y manipulación

sobre objetos que sólo se conocen al ejecutar el paquete.

Un ejemplo de la utilización de dbms_sql es el siguiente:

   BEGIN

      ......

      id_cursor := DBMS_SQL.OPEN_CURSOR;

      DMBS_SQL.PARSE(id_cursor, instrucción,DMBS_SQL.V3);

      v_dum :=DMBS_SQL.EXECUTE(id_cursor);

      DMBS_SQL.CLOSE_CURSOR(id_cursor);

   ......

Lo que hacemos es abrir el cursor y nos devuelve el id del mismo para poder trabajar con él.

Después tenemos el DMBS_SQL.PARSE que analiza la instrucción que se va a ejecutar. Ya en

la siguiente linea ejecutamos la sentencia y por último cerramos el cursor.

No os preocupéis si no habéis terminado de entenderlo ya que dedicaremos un articulo

completo a la utilización de DBSM_SQL.