0% encontró este documento útil (0 votos)
87 vistas58 páginas

PL SQL

El documento describe los diferentes tipos de operadores y estructuras de control en PL/SQL, incluyendo operadores aritméticos, relacionales, lógicos y de concatenación, así como las estructuras condicionales IF y CASE, los bucles FOR, WHILE y LOOP, y el uso de cursores y excepciones.

Cargado por

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

PL SQL

El documento describe los diferentes tipos de operadores y estructuras de control en PL/SQL, incluyendo operadores aritméticos, relacionales, lógicos y de concatenación, así como las estructuras condicionales IF y CASE, los bucles FOR, WHILE y LOOP, y el uso de cursores y excepciones.

Cargado por

Jean Alvarez
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como DOCX, PDF, TXT o lee en línea desde Scribd

Operadores en PL/SQL

La siguiente tabla ilustra los operadores de PL/SQL.


Tipo de operador

Operadores

Operador de
asignacin

:= (dos puntos + igual)

Operadores
aritmticos

+ (suma)
- (resta)
* (multiplicacin)
/ (divisin)
** (exponente)

Operadores
relacionales o de
comparacin

= (igual a)
<> (distinto de)
< (menor que)
> (mayor que)
>= (mayor o igual a)
<= (menor o igual a)

Operadores lgicos

AND (y lgico)
NOT (negacion)
OR (o lgico)

Operador de
concatenacin

||

Estructuras de control en PL/SQL


Estrcuturas de control de flujo
En PL/SQL solo disponemos de la estructura condicional IF. Su sintaxis se muestra
a continuacin:

IF (expresion) THEN
-- Instrucciones
ELSIF (expresion) THEN
-- Instrucciones
ELSE
-- Instrucciones
END IF;
Un aspecto a tener en cuenta es que la instruccin condicional anidada
es ELSIF y no "ELSEIF".

Sentencia GOTO
PL/SQL dispone de la sentencia GOTO. La sentencia GOTO desvia el flujo de
ejecuci a una determinada etiqueta.
En PL/SQL las etiquetas se indican del siguiente modo: << etiqueta >>
El siguiente ejemplo ilustra el uso de GOTO.

DECLARE
flag NUMBER;
BEGIN
flag :=1 ;
IF (flag = 1) THEN
GOTO paso2;
END IF;
<<paso1>>
dbms_output.put_line('Ejecucion de paso 1');
<<paso2>>
dbms_output.put_line('Ejecucion de paso 2');
END;

Bucles
En PL/SQL tenemos a nuestra disposicin los siguientes iteradores o bucles:

LOOP

WHILE

FOR
El bucle LOOP, se repite tantas veces como sea necesario hasta que se fuerza su
salida con la instruccin EXIT. Su sintaxis es la siguiente

LOOP

-- Instrucciones
IF (expresion) THEN
-- Instrucciones
EXIT;
END IF;
END LOOP;

El bucle WHILE, se repite mientras que se cumpla expresion.

WHILE (expresion) LOOP


-- Instrucciones
END LOOP;
El bucle FOR, se repite tanta veces como le indiquemos en los
identificadores inicio y final.
FOR contador IN [REVERSE] inicio..final LOOP
-- Instrucciones
END LOOP;

En el caso de especificar REVERSE el bucle se recorre en sentido inverso.

Bloques PL/SQL

Un programa de PL/SQL est compuesto por bloques. Un programa est


compuesto como mnimo de un bloque.
Los bloques de PL/SQL pueden ser de los siguientes tipos:

Bloques annimos

Subprogramas

Estructura de un Bloque
Los bloques PL/SQL presentan una estructura especfica compuesta de tres
partes bien diferenciadas:

La seccin declarativa en donde se declaran todas las constantes y variables


que se van a utilizar en la ejecucin del bloque.

La seccin de ejecucin que incluye las instrucciones a ejecutar en el bloque


PL/SQL.

La seccin de excepciones en donde se definen los manejadores de errores


que soportar el bloque PL/SQL.
Cada una de las partes anteriores se delimita por una palabra reservada, de modo
que un bloque PL/SQL se puede representar como sigue:

[ declare | is | as ]
/*Parte declarativa*/
begin

/*Parte de ejecucion*/
[ exception ]
/*Parte de excepciones*/
end;
De las anteriores partes, nicamente la seccin de ejecucin es obligatoria, que
quedara delimitada entre las clusulas BEGIN yEND. Veamos un ejemplo de
bloque PL/SQL muy genrico. Se trata de un bloque annimos, es decir no lo
identifica ningn nombre. Los bloques annimos identifican su parte declarativa con
la palabra reservada DECLARE.

DECLARE
/*Parte declarativa*/
nombre_variable DATE;
BEGIN

/*Parte de ejecucion
* Este cdigo asigna el valor de la columna "nombre_columna"
* a la variable identificada por "nombre_variable"
*/
SELECT SYSDATE
INTO nombre_variable
FROM DUAL;

EXCEPTION

END;

/*Parte de excepciones*/
WHEN OTHERS THEN
dbms_output.put_line('Se ha producido un error');

A continuacin vamos a ver cada una de estas secciones

Seccin de Declaracin de Variables


En esta parte se declaran las variables que va a necesitar nuestro programa. Una
variable se declara asignandole un nombre o "identificador" seguido del tipo de
valor que puede contener. Tambin se declaran cursores, de gran utilidad para la
consulta de datos, y excepciones definidas por el usuario. Tambin podemos
especificar si se trata de una constante, si puede contener valor nulo y asignar un
valor inicial.
La sintaxis generica para la declaracion de constantes y variables es:

nombre_variable [CONSTANT] <tipo_dato> [NOT NULL][:=valor_inicial]


donde:

tipo_dato: es el tipo de dato que va a poder almacenar la variable, este


puede ser cualquiera de los tipos soportandos por ORACLE, es
decir NUMBER , DATE , CHAR , VARCHAR, VARCHAR2, BOOLEAN ... Adems
para algunos tipos de datos (NUMBER y VARCHAR) podemos especificar la longitud.

La clusula CONSTANT indica la definicin de una constante cuyo valor no


puede ser modificado. Se debe incluir la inicializacin de la constante en su
declaracin.

La clusula NOT NULL impide que a una variable se le asigne el valor nulo, y
por tanto debe inicializarse a un valor diferente de NULL.

Las variables que no son inicializadas toman el valor inicial NULL.

La inicializacin puede incluir cualquier expresin legal de PL/SQL, que


lgicamente debe corresponder con el tipo del identificador definido.

Los tipos escalares incluyen los definidos en SQL ms los tipos VARCHAR y
BOOLEAN. Este ltimo puede tomar los valores TRUE, FALSE y NULL, y se suele
utilizar para almacenar el resultado de alguna operacin lgica. VARCHAR es un
sinnimo de CHAR.

Tambin es posible definir el tipo de una variable o constante, dependiendo


del tipo de otro identificador, mediante la utilizacin de las
clusulas %TYPE y %ROWTYPE. Mediante la primera opcin se define una variable
o constante escalar, y con la segunda se define una variable fila, donde
identificador puede ser otra variable fila o una tabla. Habitualmente se utiliza
%TYPE para definir la variable del mismo tipo que tenga definido un campo en una
tabla de la base de datos, mientras que%ROWTYPE se utiliza para declarar
varibales utilizando cursores.

Ejemplos:
Estructura de un bloque annimo.

DECLARE
/* Se declara la variable de tipo VARCHAR2(15) identificada por v_location y se
le asigna
el valor "Granada"*/
v_location VARCHAR2(15) := Granada;

asigna

/*Se declara la constante de tipo NUMBER identificada por PI y se le


el valor 3.1416*/
PI CONSTANT NUMBER := 3.1416;

/*Se declara la variable del mismo tipo que tenga el campo nombre de la
tabla tabla_empleados
identificada por v_nombre y no se le asigna ningn valor */
v_nombre tabla_empleados.nombre%TYPE;
/*Se declara la variable del tipo registro correspondiente a un supuesto
cursor, llamado
micursor, identificada por reg_datos*/
reg_datos micursor%ROWTYPE;
BEGIN
/*Parte de ejecucion*/
EXCEPTION
/*Parte de excepciones*/
END;
Estructura de un subprograma:

CREATE PROCEDURE simple_procedure IS


/* Se declara la variable de tipo VARCHAR2(15) identificada por v_location y se
le asigna
el valor "Granada"*/
v_location VARCHAR2(15) := Granada;

asigna

/*Se declara la constante de tipo NUMBER identificada por PI y se le


el valor 3.1416*/
PI CONSTANT NUMBER := 3.1416;

/*Se declara la variable del mismo tipo que tenga el campo nombre de la
tabla tabla_empleados
identificada por v_nombre y no se le asigna ningn valor */
v_nombre tabla_empleados.nombre%TYPE;
/*Se declara la variable del tipo registro correspondiente a un supuesto
cursor, llamado

micursor, identificada por reg_datos*/


reg_datos micursor%ROWTYPE;
BEGIN
/*Parte de ejecucion*/
EXCEPTION
/*Parte de excepciones*/
END;

Cursores en PL/SQL
Introduccin a cursores PL/SQL
PL/SQL utiliza cursores para gestionar las instrucciones SELECT. Un cursor es un
conjunto de registros devuelto por una instruccin SQL. Tcnicamente los cursores
son fragmentos de memoria que reservados para procesar los resultados de una
consulta SELECT.
Podemos distinguir dos tipos de cursores:

Cursores implicitos. Este tipo de cursores se utiliza para


operaciones SELECT INTO. Se usan cuando la consulta devuelve un nico registro.

Cursores explicitos. Son los cursores que son declarados y controlados por
el programador. Se utilizan cuando la consulta devuelve un conjunto de registros.
Ocasionalmente tambin se utilizan en consultas que devuelven un nico registro
por razones de eficiencia. Son ms rpidos.
Un cursor se define como cualquier otra variable de PL/SQL y debe nombrarse de
acuerdo a los mismos convenios que cualquier otra variable. Los cursores implicitos
no necesitan declaracin.
El siguiente ejemplo declara un cursor explicito:

declare
cursor c_paises is
SELECT CO_PAIS, DESCRIPCION
FROM PAISES;
begin
/* Sentencias del bloque ...*/
end;

Para procesar instrucciones SELECT que devuelvan ms de una fila, son


necesarios cursores explicitos combinados con un estructura de bloque.

Un cursor admite el uso de parmetros. Los parmetros deben declararse junto


con el cursor.
El siguiente ejemplo muestra la declaracion de un cursor con un parmetro,
identificado por p_continente.

declare
cursor c_paises (p_continente IN VARCHAR2) is
SELECT CO_PAIS, DESCRIPCION
FROM PAISES
WHERE CONTINENTE = p_continente;
begin
/* Sentencias del bloque ...*/
end;

El siguiente diagrama representa como se procesa una instruccin SQL a travs


de un cursor.

Fases para procesar una instruccin SQL

Cursores Implicitos
Declaracin de cursores implicitos.
Los cursores implicitos se utilizan para realizar consultas SELECT que devuelven
un nico registro.
Deben tenerse en cuenta los siguientes puntos cuando se utilizan cursores
implicitos:

Con cada cursor implicito debe existir la palabra clave INTO.


Las variables que reciben los datos devueltos por el cursor tienen que
contener el mismo tipo de dato que las columnas de la tabla.

Los cursores implicitos solo pueden devolver una nica fila. En caso de que
se devuelva ms de una fila (o ninguna fila) se producir una excepcion. No se
preocupe si an no sabe que es una excepcion, le valdr conocer que es el medio
por el que PL/SQL gestiona los errores.
El siguiente ejemplo muestra un cursor implicito:

declare
vdescripcion VARCHAR2(50);
begin
SELECT DESCRIPCION
INTO vdescripcion
from PAISES
WHERE CO_PAIS = 'ESP';
dbms_output.put_line('La lectura del cursor es: ' || vdescripcion);
end;

La salida del programa generara la siguiente lnea:

La lectura del cursor es: ESPAA

Excepciones asociadas a los cursores implicitos.


Los cursores implicitos slo pueden devolver una fila, por lo que pueden
producirse determinadas excepciones. Las ms comunes que se pueden encontrar
son no_data_found y too_many_rows. La siguiente tabla explica brevemente
estas excepciones.

Excepcion
NO_DATA_FOUND

Explicacion

Se produce cuando una sentencia SELECT intenta recuperar datos pero ninguna fila satisface sus
condiciones. Es decir, cuando "no hay datos"
TOO_MANY_ROWS Dado que cada cursor implicito slo es capaz de recuperar una fila , esta excepcion detecta la
existencia de ms de una fila.

Cursores Explicitos en PL/SQL


Declaracin de cursores explicitos
Los cursores explicitos se emplean para realizar consultas SELECT que pueden
devolver cero filas, o ms de una fila.
Para trabajar con un cursor explicito necesitamos realizar las siguientes tareas:

Declarar el cursor.

Abrir el cursor con la instruccin OPEN.

Leer los datos del cursor con la instruccin FETCH.

Cerrar el cursor y liberar los recursos con la instruccin CLOSE.


Para declarar un cursor debemos emplear la siguiente sintaxis:

CURSOR nombre_cursor IS
instruccin_SELECT
Tambin debemos declarar los posibles parametros que requiera el cursor:

CURSOR nombre_cursor(param1 tipo1, ..., paramN tipoN) IS


instruccin_SELECT

Para abrir el cursor

OPEN nombre_cursor;
o bien (en el caso de un cursor con parmetros)
OPEN nombre_cursor(valor1, valor2, ..., valorN);
Para recuperar los datos en variables PL/SQL.

FETCH nombre_cursor INTO lista_variables;


-- o bien ...
FETCH nombre_cursor INTO registro_PL/SQL;
Para cerrar el cursor:

CLOSE nombre_cursor;
El siguiente ejemplo ilustra el trabajo con un cursor explicito. Hay que tener en
cuenta que al leer los datos del cursor debemos hacerlo sobre variables del mismo
tipo de datos de la tabla (o tablas) que trata el cursor.

DECLARE
CURSOR cpaises
IS
SELECT CO_PAIS, DESCRIPCION, CONTINENTE
FROM PAISES;

co_pais VARCHAR2(3);
descripcion VARCHAR2(50);
continente VARCHAR2(25);
BEGIN
OPEN cpaises;
FETCH cpaises INTO co_pais,descripcion,continente;
CLOSE cpaises;
END;
Podemos simplificar el ejemplo utilizando el atributo de tipo %ROWTYPE sobre el
cursor.

DECLARE
CURSOR cpaises
IS
SELECT CO_PAIS, DESCRIPCION, CONTINENTE
FROM PAISES;
registro cpaises%ROWTYPE;

BEGIN
OPEN cpaises;
FETCH cpaises INTO registro;
CLOSE cpaises;
END;
El mismo ejemplo, pero utilizando parmetros:

DECLARE
CURSOR cpaises (p_continente VARCHAR2)
IS
SELECT CO_PAIS, DESCRIPCION, CONTINENTE
FROM PAISES
WHERE CONTINENTE = p_continente;
registro cpaises%ROWTYPE;
BEGIN
OPEN cpaises('EUROPA');
FETCH cpaises INTO registro;
CLOSE cpaises;
END;
Cuando trabajamos con cursores debemos considerar:

Cuando un cursor est cerrado, no se puede leer.


Cuando leemos un cursor debemos comprobar el resultado de la lectura
utilizando los atributos de los cursores.

Cuando se cierra el cursor, es ilegal tratar de usarlo.

Es ilegal tratar de cerrar un cursor que ya est cerrado o no ha sido abierto

Atributos de cursores

Toman los valores TRUE, FALSE o NULL dependiendo de la situacin:

Atributo

%NOTFOUN
D
%FOUND
%ISOPEN
%ROWCOUN
T

Antes de
abrir

Al
abrir

Durante la
recuperacin

Al finalizar la
recuperacin

Despus de cerrar

ORA-1001 NULL FALSE

TRUE

ORA-1001

ORA-1001 NULL TRUE


FALSE
TRUE TRUE

FALSE
TRUE

ORA-1001
FALSE

ORA-1001 0

**

ORA-1001

* Nmero de registros que ha recuperado hasta el momento


** Nmero de total de registros

Manejo del cursor


Por medio de ciclo LOOP podemos iterar a travs del cursor. Debe tenerse
cuidado de agregar una condicin para salir del bucle:
Vamos a ver varias formas de iterar a travs de un cursor. La primera es
utilizando un bucle LOOP con una sentencia EXIT condicionada:

OPEN nombre_cursor;
LOOP
FETCH nombre_cursor INTO lista_variables;
EXIT WHEN nombre_cursor%NOTFOUND;
/* Procesamiento de los registros recuperados */
END LOOP;
CLOSE nombre_cursor;

Aplicada a nuestro ejemplo anterior:

DECLARE
CURSOR cpaises
IS
SELECT CO_PAIS, DESCRIPCION, CONTINENTE
FROM PAISES;
co_pais VARCHAR2(3);
descripcion VARCHAR2(50);
continente VARCHAR2(25);
BEGIN
OPEN cpaises;
LOOP
FETCH cpaises INTO co_pais,descripcion,continente;
EXIT WHEN cpaises%NOTFOUND;
dbms_output.put_line(descripcion);
END LOOP;
CLOSE cpaises;
END;

Otra forma es por medio de un bucle WHILE LOOP. La instruccin FECTH aparece
dos veces.

OPEN nombre_cursor;
FETCH nombre_cursor INTO lista_variables;
WHILE nombre_cursor%FOUND
LOOP
/* Procesamiento de los registros recuperados */
FETCH nombre_cursor INTO lista_variables;
END LOOP;
CLOSE nombre_cursor;

DECLARE
CURSOR cpaises
IS
SELECT CO_PAIS, DESCRIPCION, CONTINENTE
FROM PAISES;
co_pais VARCHAR2(3);
descripcion VARCHAR2(50);
continente VARCHAR2(25);
BEGIN
OPEN cpaises;
FETCH cpaises INTO co_pais,descripcion,continente;
WHILE cpaises%found
LOOP
dbms_output.put_line(descripcion);
FETCH cpaises INTO co_pais,descripcion,continente;
END LOOP;
CLOSE cpaises;
END;

Por ltimo podemos usar un bucle FOR LOOP. Es la forma ms corta ya que el
cursor es implicitamente se ejecutan las instrucciones OPEN, FECTH y CLOSE.

FOR variable IN nombre_cursor LOOP


/* Procesamiento de los registros recuperados */
END LOOP;

BEGIN
FOR REG IN (SELECT * FROM PAISES)
LOOP
dbms_output.put_line(reg.descripcion);
END LOOP;
END;

Excepciones en PL/SQL
Manejo de excepciones
En PL/SQL una advertencia o condicin de error es llamada una excepcin.
Las excepciones se controlan dentro de su propio bloque.La estructura de bloque
de una excepcin se muestra a continuacin.

DECLARE
-- Declaraciones
BEGIN
-- Ejecucion
EXCEPTION
-- Excepcion
END;
Cuando ocurre un error, se ejecuta la porcin del programa marcada por el
bloque EXCEPTION, transfirindose el control a ese bloque de sentencias.
El siguiente ejemplo muestra un bloque de excepciones que captura las
excepciones NO_DATA_FOUND y ZERO_DIVIDE.Cualquier otra excepcion ser
capturada en el bloque WHEN OTHERS THEN.

DECLARE
-- Declaraciones
BEGIN
-- Ejecucion
EXCEPTION
WHEN NO_DATA_FOUND THEN
-- Se ejecuta cuando ocurre una excepcion de tipo NO_DATA_FOUND
WHEN ZERO_DIVIDE THEN
-- Se ejecuta cuando ocurre una excepcion de tipo ZERO_DIVIDE
WHEN OTHERS THEN
-- Se ejecuta cuando ocurre una excepcion de un tipo no tratado
-- en los bloques anteriores
END;
Como ya hemos dicho cuando ocurre un error, se ejecuta el bloque EXCEPTION,
transfirindose el control a las sentencias del bloque. Una vez finalizada la ejecucin
del bloque de EXCEPTION no se continua ejecutando el bloque anterior.
Si existe un bloque de excepcion apropiado para el tipo de excepcin se ejecuta
dicho bloque. Si no existe un bloque de control de excepciones adecuado al tipo de
excepcion se ejecutar el bloque de excepcion WHEN OTHERS THEN (si
existe!). WHEN OTHERSdebe ser el ltimo manejador de excepciones.
Las excepciones pueden ser definidas en forma interna o explcitamente por el
usuario. Ejemplos de excepciones definidas en forma interna son la divisin por cero
y la falta de memoria en tiempo de ejecucin. Estas mismas condiciones
excepcionales tienen sus propio tipos y pueden ser referenciadas por
ellos: ZERO_DIVIDE y STORAGE_ERROR.
Las excepciones definidas por el usuario deben ser alcanzadas explcitamente
utilizando la sentencia RAISE.
Con las excepciones se pueden manejar los errores cmodamente sin necesidad
de mantener mltiples chequeos por cada sentencia escrita. Tambin provee
claridad en el cdigo ya que permite mantener las rutinas correspondientes al
tratamiento de los errores de forma separada de la lgica del negocio.

Excepciones predefinidas
PL/SQL proporciona un gran nmero de excepciones predefinidas que permiten
controlar las condiciones de error ms habituales.
Las excepciones predefinidas no necesitan ser declaradas. Simplemente se
utilizan cuando estas son lanzadas por algn error determinado.
La siguiente es la lista de las excepciones predeterminadas por PL/SQL y una
breve descripcin de cundo son accionadas:

Excepcion
ACCESS_INTO_NULL
COLLECTION_IS_NULL

Se ejecuta ...
El programa intent asignar valores a los atributos
de un objeto no inicializado
El programa intent asignar valores a una tabla

SQLCODE
-6530
-6531

anidada an no inicializada
El programa intent abrir un cursor que ya se
encontraba abierto. Recuerde que un cursor de
CURSOR_ALREADY_OPEN
-6511
ciclo FOR automticamente lo abre y ello no se
debe especificar con la sentencia OPEN
El programa intent almacenar valores duplicados
DUP_VAL_ON_INDEX
en una columna que se mantiene con restriccin de -1
integridad de un ndice nico (unique index)
El programa intent efectuar una operacin no
INVALID_CURSOR
-1001
vlida sobre un cursor
En una sentencia SQL, la conversin de una cadena
INVALID_NUMBER
de caracteres hacia un nmero falla cuando esa
-1722
cadena no representa un nmero vlido
El programa intent conectarse a Oracle con un
LOGIN_DENIED
-1017
nombre de usuario o password invlido
Una sentencia SELECT INTO no devolvi valores o el
NO_DATA_FOUND
programa referenci un elemento no inicializado en 100
una tabla indexada
El programa efectu una llamada a Oracle sin estar
NOT_LOGGED_ON
-1012
conectado
PROGRAM_ERROR
PL/SQL tiene un problema interno
-6501
Los elementos de una asignacin (el valor a asignar
y la variable que lo contendr) tienen tipos
ROWTYPE_MISMATCH
incompatibles. Tambin se presenta este error
-6504
cuando un parmetro pasado a un subprograma no
es del tipo esperado
El parmetro SELF (el primero que es pasado a un
SELF_IS_NULL
-30625
mtodo MEMBER) es nulo
STORAGE_ERROR
La memoria se termin o est corrupta
-6500
El programa est tratando de referenciar un
SUBSCRIPT_BEYOND_COUN elemento de un arreglo indexado que se encuentra
-6533
T
en una posicin ms grande que el nmero real de
elementos de la coleccin
El programa est referenciando un elemento de un
SUBSCRIPT_OUTSIDE_LIMI
arreglo utilizando un nmero fuera del rango
-6532
T
permitido (por ejemplo, el elemento -1)
La conversin de una cadena de caracteres hacia
SYS_INVALID_ROWID
un tipo rowid fall porque la cadena no representa -1410
un nmero
Se excedi el tiempo mximo de espera por un
TIMEOUT_ON_RESOURCE
-51
recurso en Oracle
Una sentencia SELECT INTO devuelve ms de una
TOO_MANY_ROWS
-1422
fila
Ocurri un error aritmtico, de conversin o
truncamiento. Por ejemplo, sucede cuando se
VALUE_ERROR
-6502
intenta calzar un valor muy grande dentro de una
variable ms pequea
ZERO_DIVIDE
El programa intent efectuar una divisin por cero -1476

Excepciones personalizadas en PL/SQL


RAISE_APPLICATION_ERROR
En ocasiones queremos enviar un mensaje de error personalizado al producirse
una excepcin PL/SQL.
Para ello es necesario utilizar la instruccion RAISE_APPLICATION_ERROR;
La sintaxis general es la siguiente:

RAISE_APPLICATION_ERROR(<error_num>,<mensaje>);
Siendo:

error_num es un entero negativo comprendido entre -20001 y -20999

mensaje la descripcion del error

DECLARE
v_div NUMBER;
BEGIN
SELECT 1/0 INTO v_div FROM DUAL;
EXCEPTION
WHEN OTHERS THEN
RAISE_APPLICATION_ERROR(-20001,'No se puede dividir por cero');

END;

Procedimientos almacenados
Un procedimiento es un subprograma que ejecuta una accin especifica y que no
devuelve ningn valor. Un procedimiento tiene un nombre, un conjunto de
parmetros (opcional) y un bloque de cdigo.
La sintaxis de un procedimiento almacenado es la siguiente:

CREATE [OR REPLACE]


PROCEDURE <procedure_name> [(<param1> [IN|OUT|IN OUT] <type>,
<param2> [IN|OUT|IN OUT] <type>, ...)]
IS
-- Declaracion de variables locales
BEGIN
-- Sentencias
[EXCEPTION]
-- Sentencias control de excepcion
END [<procedure_name>];
El uso de OR REPLACE permite sobreescribir un procedimiento existente. Si se
omite, y el procedimiento existe, se producir, un error.
La sintaxis es muy parecida a la de un bloque annimo, salvo porque se
reemplaza la seccion DECLARE por la secuenciaPROCEDURE ... IS en la
especificacin del procedimiento.

Debemos especificar el tipo de datos de cada parmetro. Al especificar el tipo


de dato del parmetro no debemos especificar la longitud del tipo.
Los parmetros pueden ser de entrada (IN), de salida (OUT) o de entrada salida
(IN OUT). El valor por defecto es IN, y se toma ese valor en caso de que no
especifiquemos nada.

CREATE OR REPLACE
PROCEDURE Actualiza_Saldo(cuenta NUMBER,
new_saldo NUMBER)
IS
-- Declaracion de variables locales
BEGIN
-- Sentencias
UPDATE SALDOS_CUENTAS
SET SALDO = new_saldo,
FX_ACTUALIZACION = SYSDATE
WHERE CO_CUENTA = cuenta;
END Actualiza_Saldo;
Tambin podemos asignar un valor por defecto a los parmetros, utilizando la
clausula DEFAULT o el operador de asigancin (:=) .

CREATE OR REPLACE
PROCEDURE Actualiza_Saldo(cuenta NUMBER,
new_saldo NUMBER DEFAULT 10 )
IS
-- Declaracion de variables locales
BEGIN
-- Sentencias
UPDATE SALDOS_CUENTAS
SET SALDO = new_saldo,
FX_ACTUALIZACION = SYSDATE
WHERE CO_CUENTA = cuenta;
END Actualiza_Saldo;
Una vez creado y compilado el procedimiento almacenado podemos ejecutarlo. Si
el sistema nos indica que el procedimiento se ha creado con errores de compilacin
podemos ver estos errores de compilacion con la orden SHOW ERRORS en SQL
*Plus.
Existen dos formas de pasar argumentos a un procedimiento almacenado a la
hora de ejecutarlo (en realidad es vlido para cualquier subprograma). Estas son:

Notacin posicional: Se pasan los valores de los parmetros en el mismo


orden en que el procedure los define.

BEGIN
Actualiza_Saldo(200501,2500);
COMMIT;

END;

Notacin nominal:Se pasan los valores en cualquier orden nombrando


explicitamente el parmetro.

BEGIN
Actualiza_Saldo(cuenta => 200501,new_saldo
COMMIT;

=> 2500);

END;

Funciones en PL/SQL
Una funcin es un subprograma que devuelve un valor.
La sintaxis para construir funciones es la siguiente:

CREATE [OR REPLACE]


FUNCTION <fn_name>[(<param1> IN <type>, <param2> IN <type>, ...)]
RETURN <return_type>
IS
result <return_type>;
BEGIN
return(result);
[EXCEPTION]
-- Sentencias control de excepcion
END [<fn_name>];
El uso de OR REPLACE permite sobreescribir una funcin existente. Si se omite, y
la funcin existe, se producir, un error.
La sintaxis de los parmetros es la misma que en los procedimientos
almacenado, exceptuando que solo pueden ser de entrada.
Ejemplo:

CREATE OR REPLACE

FUNCTION fn_Obtener_Precio(p_producto VARCHAR2)


RETURN NUMBER
IS
result NUMBER;
BEGIN
SELECT PRECIO INTO result
FROM PRECIOS_PRODUCTOS
WHERE CO_PRODUCTO = p_producto;
return(result);
EXCEPTION
WHEN NO_DATA_FOUND THEN
return 0;
END ;
Si el sistema nos indica que el la funcin se ha creado con errores de compilacin
podemos ver estos errores de compilacion con la orden SHOW ERRORS en SQL
*Plus.
Una vez creada y compilada la funcin podemos ejecutarla de la siguiente forma:

DECLARE
Valor NUMBER;
BEGIN

Valor := fn_Obtener_Precio('000100');

END;
Las funciones pueden utilizarse en sentencias SQL de manipulacin de datos
(SELECT, UPDATE, INSERT y DELETE):

SELECT CO_PRODUCTO,
DESCRIPCION,
fn_Obtener_Precio(CO_PRODUCTO)
FROM PRODUCTOS;

Triggers
Declaracin de triggers
Un trigger es un bloque PL/SQL asociado a una tabla, que se ejecuta como
consecuencia de una determinada instruccin SQL (una operacin DML: INSERT,
UPDATE o DELETE) sobre dicha tabla.
La sintaxis para crear un trigger es la siguiente:

CREATE [OR REPLACE] TRIGGER <nombre_trigger>


{BEFORE|AFTER}
{DELETE|INSERT|UPDATE [OF col1, col2, ..., colN]
[OR {DELETE|INSERT|UPDATE [OF col1, col2, ..., colN]...]}
ON <nombre_tabla>
[FOR EACH ROW [WHEN (<condicion>)]]
DECLARE
-- variables locales
BEGIN
-- Sentencias
[EXCEPTION]
-- Sentencias control de excepcion
END <nombre_trigger>;
El uso de OR REPLACE permite sobreescribir un trigger existente. Si se omite, y el
trigger existe, se producir, un error.
Los triggers pueden definirse para las operaciones INSERT, UPDATE o DELETE, y
pueden ejecutarse antes o despus de la operacin. El modificador BEFORE AFTER
indica que el trigger se ejecutar antes o despues de ejecutarse la sentencia SQL
definida por DELETE INSERT UPDATE. Si incluimos el modificador OF el trigger solo
se ejecutar cuando la sentencia SQL afecte a los campos incluidos en la lista.
El alcance de los disparadores puede ser la fila o de orden. El modificador FOR
EACH ROW indica que el trigger se disparar cada vez que se realizan operaciones

sobre una fila de la tabla. Si se acompaa del modificador WHEN, se establece una
restriccin; el trigger solo actuar, sobre las filas que satisfagan la restriccin.
La siguiente tabla resume los contenidos anteriores.

Valor
INSERT, DELETE, UPDATE
BEFORE , AFTER
FOR EACH ROW

Descripcin
Define qu tipo de orden DML provoca la activacin del disparador.
Define si el disparador se activa antes o despus de que se ejecute la orden.
Los disparadores con nivel de fila se activan una vez por cada fila afectada por la
orden que provoc el disparo. Los disparadores con nivel de orden se activan slo
una vez, antes o despus de la orden. Los disparadores con nivel de fila se
identifican por la clusula FOR EACH ROW en la definicin del disparador.

La clusula WHEN slo es vlida para los disparadores con nivel de fila.
Dentro del ambito de un trigger disponemos de las variables OLD y NEW . Estas
variables se utilizan del mismo modo que cualquier otra variable PL/SQL, con la
salvedad de que no es necesario declararlas, son de tipo %ROWTYPE y contienen
una copia del registro antes (OLD) y despues(NEW) de la accin SQL (INSERT,
UPDATE, DELTE) que ha ejecutado el trigger. Utilizando esta variable podemos
acceder a los datos que se estn insertando, actualizando o borrando.
El siguiente ejemplo muestra un trigger que inserta un registro en la tabla
PRECIOS_PRODUCTOS cada vez que insertamos un nuevo registro en la tabla
PRODUTOS:

CREATE OR REPLACE TRIGGER TR_PRODUCTOS_01


AFTER INSERT ON PRODUCTOS
FOR EACH ROW
DECLARE
-- local variables
BEGIN
INSERT INTO PRECIOS_PRODUCTOS
(CO_PRODUCTO,PRECIO,FX_ACTUALIZACION)
VALUES
(:NEW.CO_PRODUCTO,100,SYSDATE);
END ;
El trigger se ejecutar cuando sobre la tabla PRODUCTOS se ejecute
una sentencia INSERT.

INSERT INTO PRODUCTOS


(CO_PRODUCTO, DESCRIPCION)
VALUES
('000100','PRODUCTO 000100');

Orden de ejecucin de los triggers


Una misma tabla puede tener varios triggers. En tal caso es necesario conocer el
orden en el que se van a ejecutar.

Los disparadores se activan al ejecutarse la sentencia SQL.

Si existe, se ejecuta el disparador de tipo BEFORE (disparador previo) con


nivel de orden.

Para cada fila a la que afecte la orden:

Se ejecuta si existe, el disparador de tipo BEFORE con nivel de fila.

Se ejecuta la propia orden.

Se ejecuta si existe, el disparador de tipo AFTER (disparador


posterior) con nivel de fila.

Se ejecuta, si existe, el disparador de tipo AFTER con nivel de orden.

Restricciones de los triggers


El cuerpo de un trigger es un bloque PL/SQL. Cualquier orden que sea legal en un
bloque PL/SQL, es legal en el cuerpo de un disparador, con las siguientes
restricciones:

Un disparador no puede emitir ninguna orden de control de


transacciones: COMMIT, ROLLBACK o SAVEPOINT. El disparador se activa como
parte de la ejecucin de la orden que provoc el disparo, y forma parte de la misma
transaccin que dicha orden. Cuando la orden que provoca el disparo es confirmada
o cancelada, se confirma o cancela tambin el trabajo realizado por el disparador.

Por razones idnticas, ningn procedimiento o funcin llamado por el


disparador puede emitir rdenes de control de transacciones.

El cuerpo del disparador no puede contener ninguna declaracin de


variables LONG o LONG RAW

Utilizacin de :OLD y :NEW


Dentro del ambito de un trigger disponemos de las variables OLD y NEW . Estas
variables se utilizan del mismo modo que cualquier otra variable PL/SQL, con la
salvedad de que no es necesario declararlas, son de tipo %ROWTYPE y contienen
una copia del registro antes (OLD) y despues(NEW) de la accin SQL (INSERT,
UPDATE, DELTE) que ha ejecutado el trigger. Utilizando esta variable podemos
acceder a los datos que se estn insertando, actualizando o borrando.
La siguiente tabla muestra los valores de OLD y NEW.

ACCION
SQL
INSERT
UPDATE
DELETE

OLD
No definido; todos los campos toman valor
NULL.
Valores originales de la fila, antes de la
actualizacin.
Valores, antes del borrado de la fila.

NEW
Valores que sern insertados cuando se complete la
orden.
Nuevos valores que sern escritos cuando se complete la
orden.
No definidos; todos los campos toman el valor NULL.

Los registros OLD y NEW son slo vlidos dentro de los disparadores con nivel de
fila.
Podemos usar OLD y NEW como cualquier otra variable PL/SQL.

Utilizacin de predicados de los triggers: INSERTING, UPDATING y


DELETING
Dentro de un disparador en el que se disparan distintos tipos de rdenes DML
(INSERT, UPDATE y DELETE), hay tres funciones booleanas que pueden emplearse
para determinar de qu operacin se trata. Estos predicados son INSERTING,
UPDATING y DELETING.
Su comportamiento es el siguiente:

Predicado
INSERTING
UPDATING
DELETING

Comportamiento
TRUE si la orden de disparo es INSERT; FALSE en otro caso.
TRUE si la orden de disparo es UPDATE; FALSE en otro caso.
TRUE si la orden de disparo es DELETE; FALSE en otro caso.

Subprogramas en bloques annimos


Dentro de la seccion DECLARE de un bloque annimo podemos declarar
funciones y procedimientos almacenados y ejecutarlos desde el bloque de ejecucin
del script.
Este tipo de subprogramas son menos conocidos que los procedimientos
almacenados, funciones y triggers, pero son enormemente tiles.
El siguiente ejemplo declara y ejecuta utiliza una funcion (fn_multiplica_x2).

DECLARE
idx NUMBER;
FUNCTION fn_multiplica_x2(num NUMBER)
RETURN NUMBER
IS
result NUMBER;
BEGIN
result := num *2;

BEGIN

return result;
END fn_multiplica_x2;
FOR idx IN 1..10
LOOP
dbms_output.put_line
('Llamada a la funcion ... '||TO_CHAR(fn_multiplica_x2(idx)));
END LOOP;

END;
Notese que se utiliza la funcion TO_CHAR para convertir el resultado de la funcin
fn_multiplica_x2 (numrico) en alfanumrico y poder mostrar el resultado por
pantalla.

Packages en PL/SQL
Un paquete es una estructura que agrupa objetos de PL/SQL
compilados(procedures, funciones, variables, tipos ...) en la base de datos. Esto nos
permite agrupar la funcionalidad de los procesos en programas.
Lo primero que debemos tener en cuenta es que los paquetes estn formados
por dos partes: la especificacin y el cuerpo. La especificacin del un paquete y
su cuerpo se crean por separado.
La especificacin es la interfaz con las aplicaciones. En ella es posible declarar los
tipos, variables, constantes, excepciones, cursores y subprogramas disponibles para
su uso posterior desde fuera del paquete. En la especificacin del paquete slo se
declaran los objetos (procedures, funciones, variables ...), no se implementa el
cdigo. Los objetos declarados en la especificacin del paquete son accesibles
desde fuera del paquete por otro script de PL/SQL o programa. Haciendo una
analoga con el mundo de C, la especificacin es como el archivo de cabecera de un
programa en C.

Para crear la especificacin de un paquete la sintaxis general es la siguiente:

CREATE [OR REPLACE] PACKAGE <pkgName>


IS
-- Declaraciones de tipos y registros pblicas
{[TYPE <TypeName> IS <Datatype>;]}
-- Declaraciones de variables y constantes publicas
-- Tambin podemos declarar cursores
{[<ConstantName> CONSTANT <Datatype> := <valor>;]}
{[<VariableName> <Datatype>;]}
-- Declaraciones de procedimientos y funciones pblicas
{[FUNCTION <FunctionName>(<Parameter> <Datatype>,...)
RETURN <Datatype>;]}
{[PROCEDURE <ProcedureName>(<Parameter> <Datatype>, ...);]}
END <pkgName>;
El cuerpo el laimplementacin del paquete. El cuerpo del paquete debe
implementar lo que se declar inicialmente en la especificacin. Es el donde
debemos escribir el cdigo de los subprogramas. En el cuerpo de un package
podemos declarar nuevos subprogramas y tipos, pero estos seran privados para el
propio package.
La sintaxis general para crear el cuerpo de un paquete es muy parecida a la de la
especificacin, tan solo se aade la palabra claveBODY, y se implementa el cdigo
de los subprogramas.

CREATE [OR REPLACE] PACKAGE


IS

BODY

<pkgName>

-- Declaraciones de tipos y registros privados


{[TYPE <TypeName> IS <Datatype>;]}
-- Declaraciones de variables y constantes privadas
-- Tambin podemos declarar cursores
{[<ConstantName> CONSTANT <Datatype> := <valor>;]}
{[<VariableName> <Datatype>;]}
-- Implementacion de procedimientos y funciones
FUNCTION <FunctionName>(<Parameter> <Datatype>,...)
RETURN <Datatype>
IS
-- Variables locales de la funcion
BEGIN
-- Implementeacion de la funcion
return(<Result>);
[EXCEPTION]
-- Control de excepciones
END;
PROCEDURE <ProcedureName>(<Parameter> <Datatype>, ...)
IS
-- Variables locales de la funcion
BEGIN
-- Implementacion de procedimiento

[EXCEPTION]
-- Control de excepciones
END;
END <pkgName>;
El siguiente ejemplo crea un paquete llamado PKG_CONTABILIDAD.
Para crear la especificacin del paquete:

CREATE OR REPLACE PACKAGE PKG_CONTABILIDAD


IS
-- Declaraciones de tipos y registros pblicas
TYPE Cuenta_contable IS RECORD
(
codigo_cuenta VARCHAR2(6),
naturaleza
VARCHAR2(2) ,
actividad
VARCHAR2(4) ,
debe_haber
VARCHAR2(1)
);
-- Declaraciones de variables y constantes publicas
DEBE CONSTANT VARCHAR2(1) := 'D';
HABER CONSTANT VARCHAR2(1) := 'D';
ERROR_CONTABILIZAR EXCEPTION;
-- Declaraciones de procedimientos y funciones pblicas
PROCEDURE Contabilizar (mes VARCHAR2) ;
FUNCTION fn_Obtener_Saldo(codigo_cuenta VARCHAR2) RETURN NUMBER;
END PKG_CONTABILIDAD;
Aqu slo hemos declarado las variables y constantes, prototipado las funciones
y procedimientos pblicos . Es en el cuerpo del paquete cuando escribimos el
cdigo de los subprogramas Contabilizar y fn_Obtener_Saldo.

CREATE PACKAGE BODY PKG_CONTABILIDAD IS


FUNCTION fn_Obtener_Saldo(codigo_cuenta VARCHAR2)
RETURN NUMBER
IS
saldo NUMBER;
BEGIN
SELECT SALDO INTO saldo
FROM SALDOS
WHERE CO_CUENTA = codigo_cuenta;
return (saldo);
END;
PROCEDURE Contabilizar(mes VARCHAR2)
IS
CURSOR cDatos(vmes VARCHAR2)
IS
SELECT *
FROM FACTURACION
WHERE FX_FACTURACION = vmes
AND PENDIENTE_CONTABILIZAR = 'S';

fila cDatos%ROWTYPE;
BEGIN
OPEN cDatos(mes);
LOOP FETCH cDatos INTO fila;
EXIT WHEN cDatos%NOTFOUND;
/* Procesamiento de los registros recuperados */
END LOOP;
CLOSE cDatos;
EXCEPTION
WHEN OTHERS THEN
RAISE ERROR_CONTABILIZAR;
END Contabilizar;
END PKG_CONTABILIDAD;
Es posible modificar el cuerpo de un paquete sin necesidad de alterar por ello la
especificacin del mismo.
Los paquetes pueden llegar a ser programas muy complejos y suelen almacenar
gran parte de la lgica de negocio.

Registros PL/SQL
Cuando vimos los tipos de datos, omitimos intencionadamente ciertos tipos de
datos.
Estos son:

Registros

Tablas de PL

VARRAY

Declaracin de un registro.
Un registnslpwdro es una estructura de datos en PL/SQL, almacenados en
campos, cada uno de los cuales tiene su propio nombre y tipo y que se tratan como
una sola unidad lgica.

Los campos de un registro pueden ser inicializados y pueden ser definidos como
NOT NULL. Aquellos campos que no sean inicializados explcitamente, se
inicializarn a NULL.
La sintaxis general es la siguiente:

TYPE <nombre> IS RECORD


(
campo <tipo_datos> [NULL | NOT NULL]
[,<tipo_datos>...]
);
El siguiente ejemplo crea un tipo PAIS, que tiene como campos el cdigo, el
nombre y el continente.

TYPE PAIS IS RECORD


(
CO_PAIS
NUMBER ,
DESCRIPCION VARCHAR2(50),
CONTINENTE VARCHAR2(20)
);
Los registros son un tipo de datos, por lo que podremos declarar variables de
dicho tipo de datos.

DECLARE
TYPE PAIS IS RECORD
(
CO_PAIS
NUMBER ,
DESCRIPCION VARCHAR2(50),
CONTINENTE VARCHAR2(20)
);
/* Declara una variable identificada por miPAIS de tipo PAIS
Esto significa que la variable miPAIS tendr los campos
ID, DESCRIPCION y CONTINENTE.
*/
miPAIS PAIS;
BEGIN
/* Asignamos valores a los campos de la variable.
*/
miPAIS.CO_PAIS := 27;
miPAIS.DESCRIPCION := 'ITALIA';
miPAIS.CONTINENTE := 'EUROPA';
END;
Los registros pueden estar anidados. Es decir, un campo de un registro puede ser
de un tipo de dato de otro registro.

DECLARE
TYPE PAIS IS RECORD
(CO_PAIS
NUMBER ,
DESCRIPCION VARCHAR2(50),
CONTINENTE VARCHAR2(20)
);
TYPE MONEDA IS RECORD
( DESCRIPCION VARCHAR2(50),
PAIS_MONEDA PAIS );
miPAIS
PAIS;
miMONEDA MONEDA;
BEGIN
/* Sentencias
*/
END;
Pueden asignarse todos los campos de un registro utilizando una sentencia
SELECT. En este caso hay que tener cuidado en especificar las columnas en el orden
conveniente segn la declaracin de los campos del registro. Para este tipo de
asignacin es muy frecuente el uso del atributo %ROWTYPE que veremos ms
adelante.

SELECT CO_PAIS, DESCRIPCION, CONTINENTE


INTO miPAIS
FROM PAISES
WHERE CO_PAIS = 27;
Puede asignarse un registro a otro cuando sean del mismo tipo:

DECLARE
TYPE PAIS IS RECORD ...
miPAIS PAIS;
otroPAIS PAIS;
BEGIN
miPAIS.CO_PAIS := 27;
miPAIS.DESCRIPCION := 'ITALIA';
miPAIS.CONTINENTE := 'EUROPA';
otroPAIS := miPAIS;
END;

Declaracin de registros con el atributo %ROWTYPE


Se puede declarar un registro basndose en una coleccin de columnas de una
tabla, vista o cursor de la base de datos mediante el atributo %ROWTYPE.

Por ejemplo, si tengo una tabla PAISES declarada como:

CREATE TABLE PAISES(


CO_PAIS
NUMBER,
DESCRIPCION
VARCHAR2(50),
CONTINENTE
VARCHAR2(20) );
Puedo declarar una variable de tipo registro como PAISES%ROWTYPE;

DECLARE
miPAIS PAISES%ROWTYPE;
BEGIN
/* Sentencias ... */
END;
Lo cual significa que el registro miPAIS tendr la siguiente estructura: CO_PAIS
NUMBER, DESCRIPCION VARCHAR2(50), CONTINENTE VARCHAR2(20).
De esta forma se crea el registro de forma dinamic y se podrn asignar valores a
los campos de un registro a travs de un select sobre la tabla, vista o cursor a partir
de la cual se creo el registro.

Tablas PL/SQL
Declaracin de tablas de PL/SQL
Las tablas de PL/SQL son tipos de datos que nos permiten almacenar varios
valores del mismo tipo de datos.
Una tabla PL/SQL :

Es similar a un array
Tiene dos componenetes: Un ndice de tipo BINARY_INTEGER que permite
acceder a los elementos en la tabla PL/SQL y una columna de escalares o registros
que contiene los valores de la tabla PL/SQL
Puede incrementar su tamao dinmicamente.
La sintaxis general para declarar una tabla de PL es la siguiente:

TYPE <nombre_tipo_tabla> IS TABLE OF


<tipo_datos> [NOT NULL]
INDEX BY BINARY_INTEGER ;
Una vez que hemos definido el tipo, podemos declarar variables y asignarle
valores.

DECLARE
/* Definimos el tipo PAISES como tabla PL/SQL */
TYPE PAISES IS TABLE OF NUMBER INDEX BY BINARY_INTEGER ;
/* Declaramos una variable del tipo PAISES */
tPAISES PAISES;
BEGIN
tPAISES(1) := 1;
tPAISES(2) := 2;
tPAISES(3) := 3;
END;

No es posible inicializar las tablas en la inicializacin.


El rango de binary integer es 2147483647.. 2147483647, por lo tanto el ndice
puede ser negativo, lo cual indica que el ndice del primer valor no tiene que ser
necesariamente el cero.

Tablas PL/SQL de registros


Es posible declarar elementos de una tabla PL/SQL como de tipo registro.

DECLARE
TYPE PAIS IS RECORD
(
CO_PAIS
NUMBER NOT NULL ,
DESCRIPCION VARCHAR2(50),
CONTINENTE VARCHAR2(20)
);
TYPE PAISES IS TABLE OF PAIS INDEX BY BINARY_INTEGER ;
tPAISES PAISES;
BEGIN
tPAISES(1).CO_PAIS := 27;
tPAISES(1).DESCRIPCION := 'ITALIA';
tPAISES(1).CONTINENTE := 'EUROPA';
END;

Funciones para el manejo de tablas PL/SQL


Cuando trabajamos con tablas de PL podemos utilizar las siguientes funciones:

FIRST. Devuelve el menor ndice de la tabla. NULL si est vaca.

LAST. Devuelve el mayor ndice de la tabla. NULL si est vaca.


El siguiente ejemplo muestra el uso de FIRST y LAST :

DECLARE
TYPE ARR_CIUDADES IS TABLE OF VARCHAR2(50) INDEX BY BINARY_INTEGER;
misCiudades ARR_CIUDADES;
BEGIN
misCiudades(1) := 'MADRID';
misCiudades(2) := 'BILBAO';
misCiudades(3) := 'MALAGA';

END;

FOR i IN misCiudades.FIRST..misCiudades.LAST
LOOP
dbms_output.put_line(misCiudades(i));
END LOOP;

EXISTS(i). Utilizada para saber si en un cierto ndice hay almacenado un


valor. Devolver TRUE si en el ndice i hay un valor.

DECLARE
TYPE ARR_CIUDADES IS TABLE OF VARCHAR2(50) INDEX BY BINARY_INTEGER;
misCiudades ARR_CIUDADES;
BEGIN
misCiudades(1) := 'MADRID';
misCiudades(3) := 'MALAGA';
FOR i IN misCiudades.FIRST..misCiudades.LAST
LOOP
IF misCiudades.EXISTS(i) THEN
dbms_output.put_line(misCiudades(i));
ELSE
dbms_output.put_line('El elemento no existe:'||TO_CHAR(i));
END IF;
END LOOP;
END;

COUNT. Devuelve el nmero de elementos de la tabla PL/SQL.

DECLARE
TYPE ARR_CIUDADES IS TABLE OF VARCHAR2(50) INDEX BY BINARY_INTEGER;
misCiudades ARR_CIUDADES;
BEGIN
misCiudades(1) := 'MADRID';
misCiudades(3) := 'MALAGA';
/* Devuelve 2, ya que solo hay dos elementos con valor */
dbms_output.put_line(
'El nmero de elementos es:'||misCiudades.COUNT);
END;

PRIOR (n). Devuelve el nmero del ndice anterior a n en la tabla.

DECLARE
TYPE ARR_CIUDADES IS TABLE OF VARCHAR2(50) INDEX BY BINARY_INTEGER;
misCiudades ARR_CIUDADES;
BEGIN
misCiudades(1) := 'MADRID';
misCiudades(3) := 'MALAGA';
/* Devuelve 1, ya que el elemento 2 no existe */
dbms_output.put_line(
'El elemento previo a 3 es:' || misCiudades.PRIOR(3));
END;

NEXT (n). Devuelve el nmero del ndice posterior a n en la tabla.

DECLARE
TYPE ARR_CIUDADES IS TABLE OF VARCHAR2(50) INDEX BY BINARY_INTEGER;
misCiudades ARR_CIUDADES;
BEGIN
misCiudades(1) := 'MADRID';
misCiudades(3) := 'MALAGA';
/* Devuelve 3, ya que el elemento 2 no existe */
dbms_output.put_line(
'El elemento siguiente es:' || misCiudades.NEXT(1));
END;

TRIM. Borra un elemento del final de la tabla PL/SQL.

TRIM(n) borra n elementos del final de la tabla PL/SQL.

DELETE. Borra todos los elementos de la tabla PL/SQL.

DELETE(n) borra el correspondiente al ndice n.

DELETE(m,n) borra los elementos entre m y n.

VARRAYS
Definicin de VARRAYS.
Un varray se manipula de forma muy similar a las tablas de PL, pero se
implementa de forma diferente. Los elementos en el varray se almacenan
comenzando en el ndice 1 hasta la longitud mxima declarada en el tipo varray.
La sintaxis general es la siguiente:

TYPE <nombre_tipo> IS VARRAY (<tamao_maximo>) OF <tipo_elementos>;


Una consideracin a tener en cuenta es que en la declaracin de un varray el tipo
de datos no puede ser de los siguientes tipos de datos:

BOOLEAN

NCHAR

NCLOB

NVARCHAR(n)

REF CURSOR

TABLE

VARRAY
Sin embargo se puede especificar el tipo utilizando los
atributos %TYPE y %ROWTYPE.
Los VARRAY deben estar inicializados antes de poder utilizarse. Para inicializar
un VARRAY se utiliza un constructor (podemos inicializar el VARRAY en la seccin
DECLARE o bien dentro del cuerpo del bloque):

DECLARE
/* Declaramos el tipo VARRAY de cinco elementos VARCHAR2*/
TYPE t_cadena IS VARRAY(5) OF VARCHAR2(50);
/* Asignamos los valores con un constructor */
v_lista t_cadena:= t_cadena('Aitor', 'Alicia', 'Pedro','','');
BEGIN
v_lista(4) := 'Tita';
v_lista(5) := 'Ainhoa';
END;
El tamao de un VARRAY se establece mediante el nmero
de parmetros utilizados en el constructor, si declaramos un VARRAY de cinco
elementos pero al inicializarlo pasamos slo tres parmetros al constructor, el
tamao del VARRAY ser tres. Si se hacen asignaciones a elementos que queden
fuera del rango se producir un error.
El tamao de un VARRAY podr aumentarse utilizando la funcin EXTEND, pero
nunca con mayor dimensin que la definida en la declaracin del tipo. Por ejemplo,
la variable v_lista que slo tiene 3 valores definidos por lo que se podra ampliar
hasta cinco elementos pero no ms all.
Un VARRAY comparte con las tablas de PL todas las funciones vlidas para ellas,
pero aade las siguientes:

LIMIT . Devuelve el nmero maximo de elementos que admite el VARRAY.

EXTEND .Aade un elemento al VARRAY.

EXTEND(n) .Aade (n) elementos al VARRAY.

Varrays en la base de datos


Los VARRAYS pueden almacenarse en las columnas de la base de datos. Sin
embargo, un varray slo puede manipularse en su integridad, no pudiendo
modificarse sus elementos individuales de un varray.

Para poder crear tablas con campos de tipo VARRAY debemos crear el VARRAY
como un objeto de la base de datos.
La sintaxis general es:

CREATE [OR REPLACE]


TYPE <nombre_tipo> IS VARRAY (<tamao_maximo>) OF <tipo_elementos>;
Una vez que hayamos creado el tipo sobre la base de datos, podremos utilizarlo
como un tipo de datos ms en la creacion de tablas, declaracin de variables ....
Vease el siguiente ejemplo:

CREATE OR REPLACE TYPE PACK_PRODUCTOS AS VARRAY(10) OF VARCHAR2(60);


CREATE TABLE OFERTAS
(
CO_OFERTA NUMBER,
PRODUCTOS PACK_PRODUCTOS,
PRECION
NUMBER
);

Para modificar un varray almacenado, primero hay que seleccionarlo en una


variable PL/SQL. Luego se modifica la variable y se vuelve a almacenar en la tabla.
La utilizacin de VARRAYS en la base de datos est completamente
desaconsejada.

BULK COLLECT
PL/SQL nos permite leer varios registros en una tabla de PL con un nico acceso
a travs de la instruccin BULK COLLECT.
Esto nos permitir reducir el nmero de accesos a disco, por lo que
optimizaremos el rendimiento de nuestras aplicaciones. Como contrapartida el
consumo de memoria ser mayor.

DECLARE
TYPE t_descripcion IS TABLE OF PAISES.DESCRIPCION%TYPE;
TYPE t_continente IS TABLE OF PAISES.CONTINENTE%TYPE;
v_descripcion t_descripcion;
v_continente t_continente;

BEGIN
SELECT DESCRIPCION,
CONTINENTE
BULK COLLECT INTO v_descripcion, v_continente
FROM PAISES;
FOR i IN v_descripcion.FIRST .. v_descripcion.LAST LOOP
dbms_output.put_line(v_descripcion(i) || ', ' || v_continente(i));
END LOOP;
END;
/
Podemos utilizar BULK COLLECT con registros de PL.

DECLARE
TYPE PAIS IS RECORD (CO_PAIS
NUMBER ,
DESCRIPCION VARCHAR2(50),
CONTINENTE VARCHAR2(20));
TYPE t_paises IS TABLE OF PAIS;
v_paises t_paises;
BEGIN
SELECT CO_PAIS, DESCRIPCION, CONTINENTE
BULK COLLECT INTO v_paises
FROM PAISES;
FOR i IN v_paises.FIRST .. v_paises.LAST LOOP
dbms_output.put_line(v_paises(i).DESCRIPCION ||
', ' || v_paises(i).CONTINENTE);
END LOOP;
END;
/
Tambien podemos utilizar el atributo ROWTYPE.

DECLARE
TYPE t_paises IS TABLE OF PAISES%ROWTYPE;
v_paises t_paises;
BEGIN
SELECT CO_PAIS, DESCRIPCION, CONTINENTE
BULK COLLECT INTO v_paises
FROM PAISES;
FOR i IN v_paises.FIRST .. v_paises.LAST LOOP
dbms_output.put_line(v_paises(i).DESCRIPCION ||
', ' || v_paises(i).CONTINENTE);
END LOOP;
END;
/

Transacciones
Una transaccin es un conjunto de operaciones que se ejecutan en una base de
datos, y que son tratadas como una nica unidad lgica por el SGBD.
Es decir, una transaccin es una o varias sentencias SQL que se ejecutan en una
base de datos como una nica operacin, confirmandose o deshaciendose en grupo.
No todas las operaciones SQL son transaccionales. Slo son transaccionales las
operaciones correspondiente al DML, es decir,
sentencias SELECT, INSERT, UPDATE y DELETE
Para confirmar una transaccin se utiliza la sentencia COMMIT. Cuando
realizamos COMMIT los cambios se escriben en la base de datos.
Para deshacer una transaccin se utiliza la sentencia ROLLBACK. Cuando
realizamos ROLLBACK se deshacen todas las modificaciones realizadas por la

transaccin en la base de datos, quedando la base de datos en el mismo estado que


antes de iniciarse la transaccin.

Un ejemplo clsico de transaccin son las transferencias bancarias. Para realizar


una transferencia de dinero entre dos cuentas bancarias debemos descontar el
dinero de una cuenta, realizar el ingreso en la otra cuenta y grabar las operaciones
y movimientos necesarios, actuaizar los saldos ... .Si en alguno de estos puntos se
produce un fallo en el sistema podramos hacer descontado el dinero de una de las
cuentas y no haberlo ingresado en la otra. Por lo tanto, todas estas operaciones
deben ser correctas o fallar todas. En estos casos, al confirmar la transaccion
(COMMIT) o al deshacerla (ROLLBACK) garantizamos que todos los datos quedan en
un estado consistente.
En una transaccin los datos modificados no son visibles por el resto de usuarios
hasta que se confirme la transaccin.
El siguiente ejemplo muestra una supuesta transaccin bancaria:

DECLARE
importe NUMBER;
ctaOrigen VARCHAR2(23);
ctaDestino VARCHAR2(23);
BEGIN
importe := 100;
ctaOrigen := '2530 10 2000 1234567890';
ctaDestino := '2532 10 2010 0987654321';
UPDATE CUENTAS SET SALDO = SALDO - importe
WHERE CUENTA = ctaOrigen;
UPDATE CUENTAS SET SALDO = SALDO + importe
WHERE CUENTA = ctaDestino;
INSERT INTO MOVIMIENTOS
(CUENTA_ORIGEN, CUENTA_DESTINO,IMPORTE, FECHA_MOVIMIENTO)
VALUES
(ctaOrigen, ctaDestino, importe*(-1), SYSDATE);
INSERT INTO MOVIMIENTOS
(CUENTA_ORIGEN, CUENTA_DESTINO,IMPORTE, FECHA_MOVIMIENTO)
VALUES
(ctaDestino,ctaOrigen, importe, SYSDATE);
COMMIT;
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line('Error en la transaccion:'||SQLERRM);
dbms_output.put_line('Se deshacen las modificaciones);
ROLLBACK;
END;

Si alguna de las tablas afectadas por la transaccin tiene triggers, las


operaciones que realiza el trigger estn dentro del ambito de la transaccin, y son
confirmadas o deshechas conjuntamente con la transaccin.
Durante la ejecucin de una transaccin, una segunda transaccin no podr ver
los cambios realizados por la primera transaccin hasta que esta se confirme.
ORACLE es completamente transaccional. Siempre debemos especificar si que
queremos deshacer o confirmar la transacion.

Transacciones autnomas
En ocasiones es necesario que los datos escritos por parte de una transaccin
sean persistentes a pesar de que la transaccion se deshaga con ROLLBACK.
PL/SQL permite marcar un bloque con PRAGMA
AUTONOMOUS_TRANSACTION. Con esta directiva marcamos el subprograma
para que se comporte como transaccin diferente a la del proceso principal,
llevando el control de COMMIT o ROLLBACKindependiente.
Observese el siguiente ejemplo. Primero creamos un procedimiento y lo
marcamos con PRAGMA AUTONOMOUS_TRANSACTION.

CREATE OR REPLACE PROCEDURE Grabar_Log(descripcion VARCHAR2)


IS

PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
INSERT INTO LOG_APLICACION
(CO_ERROR, DESCRIPICION, FX_ERROR)
VALUES
(SQ_ERROR.NEXTVAL, descripcion, SYSDATE);
COMMIT; -- Este commit solo afecta a la transaccion autonoma
END ;
A continuacin utilizamos el procedimiento desde un bloque de PL/SQL:

DECLARE
producto PRECIOS%TYPE;
BEGIN
producto := '100599';
INSERT INTO PRECIOS
(CO_PRODUCTO, PRECIO, FX_ALTA)
VALUES
(producto, 150, SYSDATE);
COMMIT;
EXCEPTION
WHEN OTHERS THEN
Grabar_Log(SQLERRM);
ROLLBACK;
/* Los datos grabados por "Grabar_Log" se escriben en la base
de datos a pesar del ROLLBACK, ya que el procedimiento est
marcado como transaccin autonoma.
*/
END;
Es muy comn que, por ejemplo, en caso de que se produzca algn tipo de error
queramos insertar un registro en una tabla de log con el error que se ha
produccido y hacer ROLLBACK de la transaccin. Pero si hacemos ROLLBACK de la
transaccin tambien lo hacemos de la insertcin del log.

SQL Dinamico
Sentencias DML con SQL dinamico
PL/SQL ofrece la posibilidad de ejecutar sentencias SQL a partir de cadenas de
caracteres. Para ello debemos emplear la instruccinEXECUTE IMMEDIATE.
Podemos obtener informacin acerca de nmero de filas afectadas por la
instruccin ejecutada por EXEXUTE IMMEDIATEutilizando SQL%ROWCOUNT.
El siguiente ejemplo muestra la ejecucin de un comando SQL dinamico.

DECLARE

ret NUMBER;
FUNCTION fn_execute RETURN NUMBER IS
sql_str VARCHAR2(1000);
BEGIN
sql_str := 'UPDATE DATOS SET NOMBRE = ''NUEVO NOMBRE''
WHERE CODIGO = 1';
EXECUTE IMMEDIATE sql_str;
RETURN SQL%ROWCOUNT;
END fn_execute ;
BEGIN
ret := fn_execute();
dbms_output.put_line(TO_CHAR(ret));
END;
Podemos adems parametrizar nuestras consultas a travs de variables host.
Una variable host es una variable que pertenece al programa que est ejecutando
la sentencia SQL dinmica y que podemos asignar en el interior de la sentencia SQL
con la palabra claveUSING . Las variables host van precedidas de dos puntos ":".
El siguiente ejemplo muestra el uso de variables host para parametrizar una
sentencia SQL dinamica.

DECLARE
ret NUMBER;
FUNCTION fn_execute (nombre VARCHAR2, codigo NUMBER) RETURN NUMBER
IS
sql_str VARCHAR2(1000);
BEGIN
sql_str := 'UPDATE DATOS SET NOMBRE = :new_nombre
WHERE CODIGO = :codigo';
EXECUTE IMMEDIATE sql_str USING nombre, codigo;
RETURN SQL%ROWCOUNT;
END fn_execute ;
BEGIN
ret := fn_execute('Devjoker',1);
dbms_output.put_line(TO_CHAR(ret));
END;

Cursores con SQL dinmico


Con SQL dinmico tambin podemos utilizar cursores.
Para utilizar un cursor implicito solo debemos construir nuestra sentencia SELECT
en una variable de tipo caracter y ejecutarla con EXECUTE IMMEDIATE utilizando la
palabra clave INTO.

DECLARE
str_sql VARCHAR2(255);
l_cnt
VARCHAR2(20);
BEGIN

str_sql := 'SELECT count(*) FROM PAISES';


EXECUTE IMMEDIATE str_sql INTO l_cnt;
dbms_output.put_line(l_cnt);

END;
Trabajar con cursores explicitos es tambin muy fcil. nicamente destacar el uso
de REF CURSOR para declarar una variable para referirnos al cursor generado con
SQL dinamico.

DECLARE
TYPE CUR_TYP IS REF CURSOR;
c_cursor
CUR_TYP;
fila PAISES%ROWTYPE;
v_query
VARCHAR2(255);
BEGIN
v_query := 'SELECT * FROM PAISES';
OPEN c_cursor FOR v_query;
LOOP
FETCH c_cursor INTO fila;
EXIT WHEN c_cursor%NOTFOUND;
dbms_output.put_line(fila.DESCRIPCION);
END LOOP;
CLOSE c_cursor;
END;
Las varibles host tambien se pueden utilizar en los cursores.

DECLARE
TYPE cur_typ IS REF CURSOR;
c_cursor
CUR_TYP;
fila PAISES%ROWTYPE;
v_query
VARCHAR2(255);
codigo_pais VARCHAR2(3) := 'ESP';
BEGIN
v_query := 'SELECT * FROM PAISES WHERE CO_PAIS = :cpais';
OPEN c_cursor FOR v_query USING codigo_pais;
LOOP
FETCH c_cursor INTO fila;
EXIT WHEN c_cursor%NOTFOUND;
dbms_output.put_line(fila.DESCRIPCION);
END LOOP;
CLOSE c_cursor;
END;

Funciones integradas de PL/SQL


PL/SQL tiene un gran nmero de funciones incorporadas, sumamente tiles. A
continuacin vamos a ver algunas de las ms utilizadas.

SYSDATE
Devuelve la fecha del sistema:

SELECT SYSDATE FROM DUAL;

NVL

Devuelve el valor recibido como parmetro en el caso de que expresin sea


NULL,o expresin en caso contrario.

NVL(<expresion>, <valor>)
El siguiente ejemplo devuelve 0 si el precio es nulo, y el precio cuando est
informado:

SELECT CO_PRODUCTO, NVL(PRECIO, 0) FROM PRECIOS;

DECODE
Decode proporciona la funcionalidad de una sentencia de control de flujo ifelseif-else.

DECODE(<expr>, <cond1>, <val1>[, ..., <condN>, <valN>], <default>)


Esta funcin evala una expresin "<expr>", si se cumple la primera condicin
"<cond1>" devuelve el valor1 "<val1>", en caso contrario evala la siguiente
condicin y as hasta que una de las condiciones se cumpla. Si no se cumple
ninguna condicin se devuelve el valor por defecto.
Es muy comn escribir la funcin DECODE identada como si se tratase de un
bloque IF.

SELECT DECODE (co_pais, /* Expresion a evaluar */


'ESP', 'ESPAA', /* Si co_pais = 'ESP' ==> 'ESPAA' */
'MEX', 'MEXICO', /* Si co_pais = 'MEX' ==> 'MEXICO' */
'PAIS '||co_pais)/* ELSE ==> concatena */
FROM PAISES;

TO_DATE
Convierte una expresin al tipo fecha. El parmetro opcional formato indica el
formato de entrada de la expresin no el de salida.

TO_DATE(<expresion>, [<formato>])
En este ejemplo convertimos la expresion '01/12/2006' de tipo CHAR a una fecha
(tipo DATE). Con el parmetro formato le indicamos que la fecha est escrita como
da-mes-ao para que devuelve el uno de diciembre y no el doce de enero.
SELECT TO_DATE('01/12/2006',
'DD/MM/YYYY')
FROM DUAL;

Este otro ejemplo muestra la conversin con formato de da y hora.

SELECT TO_DATE('31/12/2006 23:59:59',


'DD/MM/YYYY HH24:MI:SS')
FROM DUAL;

TO_CHAR
Convierte una expresin al tipo CHAR. El parmetro opcional formato indica el
formato de salida de la expresin.

TO_CHAR(<expresion>, [<formato>])
SELECT TO_CHAR(SYSDATE, 'DD/MM/YYYYY')
FROM DUAL;

TO_NUMBER
Convierte una expresion alfanumrica en numerica. Opcionalmente podemos
especificar el formato de salida.

TO_NUMBER(<expresion>, [<formato>])

SELECT TO_NUMBER ('10')


FROM DUAL;

TRUNC
Trunca una fecha o nmero.
Si el parmetro recibido es una fecha elimina las horas, minutos y segundos de
la misma.

SELECT TRUNC(SYSDATE)FROM DUAL;


Si el parmetro es un nmero devuelve la parte entera.

SELECT TRUNC(9.99)FROM DUAL;

LENGTH
Devuelve la longitud de un tipo CHAR.

SELECT LENGTH('HOLA MUNDO')FROM DUAL;

INSTR
Busca una cadena de caracteres dentro de otra. Devuelve la posicion de la
ocurrencia de la cadena buscada.
Su sintaxis es la siguiente:

INSTR(<char>, <search_string>, <startpos>, <occurrence> )


SELECT INSTR('AQUI ES DONDE SE BUSCA', 'BUSCA', 1, 1 )
FROM DUAL;

REPLACE
Reemplaza un texto por otro en un expresion de busqueda.

REPLACE(<expresion>, <busqueda>, <reemplazo>)


El siguiente ejemplo reemplaza la palabra 'HOLA' por 'VAYA' en la cadena 'HOLA
MUNDO'.
SELECT REPLACE ('HOLA MUNDO','HOLA', 'VAYA')-- devuelve VAYA MUNDO
FROM DUAL;

SUBSTR
Obtiene una parte de una expresion, desde una posicin de inicio hasta una
determinada longitud.

SUBSTR(<expresion>, <posicion_ini>, <longitud> )


SELECT SUBSTR('HOLA MUNDO', 6, 5) -- Devuelve MUNDO
FROM DUAL;

UPPER
Convierte una expresion alfanumerica a maysculas.

SELECT UPPER('hola mundo') -- Devuelve HOLA MUNDO


FROM DUAL;

LOWER

Convierte una expresion alfanumerica a minsculas.

SELECT LOWER('HOLA MUNDO') -- Devuelve hola mundo


FROM DUAL;

ROWIDTOCHAR
Convierte un ROWID a tipo caracter.
SELECT ROWIDTOCHAR(ROWID)
FROM DUAL;

RPAD
Aade N veces una determinada cadena de caracteres a la derecha una
expresin. Muy util para generar ficheros de texto de ancho fijo.

RPAD(<expresion>, <longitud>, <pad_string> )


El siguiente ejemplo aade puntos a la expresion 'Hola mundo' hasta alcanzar
una longitud de 50 caracteres.

SELECT RPAD('Hola Mundo', 50, '.')


FROM DUAL;

LPAD
Aade N veces una determinada cadena de caracteres a la izquierda de una
expresin. Muy util para generar ficheros de texto de ancho fijo.

LPAD(<expresion>, <longitud>, <pad_string> )


El siguiente ejemplo aade puntos a la expresion 'Hola mundo' hasta alcanzar
una longitud de 50 caracteres.

SELECT LPAD('Hola Mundo', 50, '.')


FROM DUAL;

RTRIM
Elimina los espacios en blanco a la derecha de una expresion

SELECT RTRIM ('Hola Mundo


FROM DUAL;

')

LTRIM
Elimina los espacios en blanco a la izquierda de una expresion

SELECT LTRIM ('


FROM DUAL;

Hola Mundo')

TRIM
Elimina los espacios en blanco a la izquierda y derecha de una expresion

SELECT TRIM ('


FROM DUAL;

Hola Mundo

')

MOD
Devuelve el resto de la divisin entera entre dos nmeros.

MOD(<dividendo>, <divisor> )
SELECT MOD(20,15) -- Devuelve el modulo de dividir 20/15
FROM DUAL

Secuencias
ORACLE proporciona los objetos de secuencia para la generacin de cdigos
numericos automticos.
Las secuencias son una solucin fcil y elegante al problema de los codigos
autogenerados.
LA sintaxis general es la siguiente:

CREATE SEQUENCE <secuence_name>


[MINVALUE <min_val>]
[MAXVALUE <max_val>]
[START WITH <ini_val>]
[INCREMENT BY <inc_val>]
[NOCACHE | CACHE <cache_val>]
[CYCLE]
[ORDER];
El siguiente ejemplo crea una secuencia SQ_PRODUCTOS.

CREATE SEQUENCE SQ_PRODUCTOS


MINVALUE 1
MAXVALUE 999999999999999999999999999
START WITH 1
INCREMENT BY 1
CACHE 20;
Se puede simplificar la orden, tomando los valores por defecto. El ejemplo
anterior quedara del siguiente modo:

CREATE SEQUENCE SQ_PRODUCTOS;


Para obtener el siguiente valor de una secuencia debemos utilizar la
funcin NEXTVAL. NEXTVAL se puede utilizar el cualquier sentencia
SQL DML (SELECT, INSERT, UPDATE).

SELECT SQ_PRODUCTOS.NEXTVAL
FROM DUAL;
Podemos obtener el ltimo valor generado por la secuencia con la
funcin CURRVAL. Para poder ejecutar la funcin CURRVAL debemos haber
ejecutado previamente la funcin NEXTVAL.

SELECT SQ_PRODUCTOS.CURRVAL
FROM DUAL;
Para eliminar una secuencia definitivamente de la base de datos debemos utilizar
la sentencia DROP.

DROP SEQUENCE SQ_PRODUCTOS ;

PL/SQL y Java
Otra de la virtudes de PL/SQL es que permite trabajar conjuntamente con Java.
PL/SQL es un excelente lenguaje para la gestion de informacin pero en
ocasiones, podemos necesitar de un lenguaje de programacin ms potente. Por
ejemplo podramos necesitar consumir un servicio Web, conectar a otro servidor,
trabajar con Sockets .... Para estos casos podemos trabajar conjuntamente con
PL/SQL y Java.
Para poder trabajar con Java y PL/SQL debemos realizar los siguientes pasos:

Crear el programa Java y cargarlo en la base de datos.

Crear un program de recubrimiento (Wrapper) de PL/SQL.

Creacion de Objetos Java en la base de datos ORACLE.


ORACLE incorpora su propia versin de la mquina virtual Java y del JRE. Esta
versin de Java se instala conjuntamente conORACLE.
Para crear objetos Java en la base de datos podemos utilizar la uitlidad LoadJava
de ORACLE desde linea de comandos o bien crear objetos JAVA SOURCE en la
propia base de datos.
La sintaxis para la creacin de JAVA SOURCE en ORACLE es la siguiente.

CREATE [OR REPLACE] AND COMPILE


JAVA SOURCE
NAMED <JavaSourceName>
AS
public class <className>
{
<java code>
...
};
El siguiente ejemplo crea y compila una clase Java OracleJavaClass en el interior
de JAVA SOURCE FuentesJava. Un aspecto muy a tener en cuenta es que los

mtodos de la clase java que queramos invocar desde PL/SQL deben ser
estaticos.

CREATE OR REPLACE AND COMPILE


JAVA SOURCE
NAMED FuentesJava
AS
public class OracleJavaClass
{
public static String Saluda(String nombre)
{
return ("Hola desde Java" + nombre);
}
}
;
Un mismo JAVA SOURCE puede contener varias clases de Java.

CREATE OR REPLACE AND COMPILE


JAVA SOURCE
NAMED FuentesJava
AS
public class OracleJavaClass
{
public static String Saluda(String nombre)
{
return ("Hola desde Java" + nombre);
}
}
public class OracleJavaMejorada
{
public static String SaludoMejorado(String nombre)
{
return ("Saludo mejorado desde Java para:" + nombre);
}
}
;
La otra opcin sera guardar nuestro codigo java en el archivo
OracleJavaClass.java, compilarlo y cargarlo en ORACLE con LoadJava.
A continuacin se muestran ejemplos del uso de la utilidad LoadJava

loadJava -help
loadJava -u usario/password -v -f -r OracleJavaClass.class
loadJava -u usario/password -v -f -r OracleJavaClass.java

Ejecucin de programas Java con PL/SQL

Una vez que tenemos listo el programa de Java debemos integrarlo con PL/SQL.
Esto se realiza a travs de subprogramas de recubrimiento llamados Wrappers.
No podemos crear un Wrapper en un bloque anonimo.
La sintaxis general es la siguiente:

CREATE [OR REPLACE]


FUNCTION|PROCEDURE <name> [(<params>,...)]
[RETURN <tipo>]
IS|AS
LANGUAGE JAVA NAME
'<clase>.<metodo> [return <tipo>]' ;
El siguiente ejemplo muestra el Wrapper para nuestra funcin Saludo.

CREATE OR REPLACE
FUNCTION Saluda_wrap (nombre VARCHAR2)
RETURN VARCHAR2
AS
LANGUAGE JAVA NAME
'OracleJavaClass.Saluda(java.lang.String) return java.lang.String';
Una vez creado el wrapper, podremos ejecutarlo como cualquier otra funcion o
procedure de PL/SQL. Debemos crear un wrapper por cada funcin java que
queramos ejecutar desde PL/SQL.
Cuando ejecutemos el wrapper, es decir, la funcin "Saluda_wrap", internamente
se ejecutar la clase java y se invocar el mtodo esttico
"OracleJavaClass.Saluda".
Un aspecto a tener en cuenta es que es necesario proporcionar el
nombre del tipo java completo, es decir, debemos especificar
java.lang.String en lugar de nicamente String.

SELECT SALUDA_WRAP('DEVJOKER')
FROM DUAL;
La ejecucin de este ejemplo en SQL*Plus genera la siguiente salida:

SQL> SELECT SALUDA_WRAP('DEVJOKER') FROM DUAL;


SALUDA_WRAP('DEVJOKER')
---------------------------------------------Hola desde JavaDEVJOKER
Una recomendacin de diseo sera agrupar todos los Wrapper en un mismo
paquete.

En el caso de que nuestro programa Java necesitase de packages Java


adicionales, deberiamos cargarlos en la base de datos con la utilidad LoadJava.

Cc

También podría gustarte