Documentos de Académico
Documentos de Profesional
Documentos de Cultura
PL SQL
PL SQL
SQL es un lenguaje de consulta para los sistemas de bases de datos relaciónales, pero que no
posee la potencia de los lenguajes de programación.
PL/SQL amplia SQL con los elementos caracteristicos de los lenguajes de programación,
variables, sentencias de control de flujo, bucles ...
Cuando se desea realizar una aplicación completa para el manejo de una base de datos
relacional, resulta necesario utilizar alguna herramienta que soporte la capacidad de
consulta del SQL y la versatilidad de los lenguajes de programación tradicionales. PL/SQL es
el lenguaje de programación que proporciona Oracle para extender el SQL estándar con
otro tipo de instrucciones.
Para poder seguir este tutorial correctamente necesitaremos tener los siguientes
elementos:
Introducción
SQL es un lenguaje de consulta para los sistemas de bases de datos relaciónales, pero que no
posee la potencia de los lenguajes de programación. No permite el uso de
variables, estructuras de control de flujo, bucles ... y demás elementos característicos de la
programación. No es de extrañar, SQL es un lenguaje de consulta, no un lenguaje de
programación.
Sin embargo, SQL es la herramienta ideal para trabajar con bases de datos. Cuando
se desea realizar una aplicación completa para el manejo de una base de datos
relacional, resulta necesario utilizar alguna herramienta que soporte la capacidad de
consulta del SQL y la versatilidad de los lenguajes de programación tradicionales.
PL/SQL es el lenguaje de programación que proporciona Oracle para extender el SQL
estándar con otro tipo de instrucciones y elementos propios de los lenguajes de
programación.
1
Con PL/SQL vamos a poder programar las unidades de programa de la base de datos ORACLE,
están son:
Procedimientos almacenados
Funciones
Triggers
Scripts
Pero además PL/SQL nos permite realizar programas sobre las siguientes herramientas de
ORACLE:
Oracle Forms
Oracle Reports
Oracle Graphics
Oracle Aplication Server
Fundamentos de PL/SQL
Como introducción vamos a ver algunos elementos y conceptos básicos del lenguaje.
-- Linea simple
/*
Conjunto de Lineas
*/
PL/SQL proporciona una variedad predefinida de tipos de datos. Casi todos los tipos de datos
manejados por PL/SQL son similares a los soportados por SQL. A continuación se muestran
los TIPOS de DATOS más comunes:
CHAR (Caracter): Almacena datos de tipo caracter con una longitud maxima de
32767 y cuyo valor de longitud por default es 1
-- CHAR [(longitud_maxima)]
-- VARCHAR2 (longitud_maxima)
nombre VARCHAR2(20);
/* Indica que puede almacenar valores alfanuméricos de hasta 20
posiciones */
/* Cuando la longitud de los datos sea menor de 20 no se
rellena con blancos */
3
BOOLEAN (lógico): Se emplea para almacenar valores TRUE o FALSE.
hay_error BOOLEAN;
DATE (Fecha): Almacena datos de tipo fecha. Las fechas se almacenan internamente
como datos numéricos, por lo que es posible realizar operaciones aritméticas con
ellas.
Atributos de tipo. Un atributo de tipo PL/SQL es un modificador que puede ser usado
para obtener información de un objeto de la base de datos. El atributo %TYPE permite
conocer el tipo de una variable, constante o campo de la base de datos. El atributo
%ROWTYPE permite obtener los tipos de todos los campos de una tabla de la base de
datos, de una vista o de un cursor.
Existen por supuesto más tipos de datos, la siguiente tabla los muestra:
Tipo de
dato / Oracle 8i Oracle 9i Descripción
Sintáxis
Donde p es la precisión y e la
escala.
La precisión máxima La precisión máxima
dec(p, e) Por ejemplo: dec(3,1) es un
es de 38 dígitos. es de 38 dígitos.
número que tiene 2 dígitos
antes del decimal y un dígito
después del decimal.
Donde p es la precisión y e la
escala.
decimal(p, La precisión máxima La precisión máxima
Por ejemplo: decimal(3,1) es
e) es de 38 dígitos. es de 38 dígitos.
un número que tiene 2 dígitos
antes del decimal y un dígito
después del decimal.
double
precision
float
4
int
integer
Donde p es la precisión y e la
escala.
numeric(p, La precisión máxima La precisión máxima
Por ejemplo: numeric(7,2) es
e) es de 38 dígitos. es de 38 dígitos.
un número que tiene 5 dígitos
antes del decimal y 2 dígitos
después del decimal.
Donde p es la precisión y e la
escala.
number(p, La precisión máxima La precisión máxima
Por ejemplo: number(7,2) es
e) es de 38 dígitos. es de 38 dígitos.
un número que tiene 5 dígitos
antes del decimal y 2 dígitos
después del decimal.
real
smallint
Hasta 32767 bytes en Hasta 32767 bytes en
Donde tamaño es el número
PLSQL. PLSQL.
char de caracteres a almacenar.
(tamaño) Son cadenas de ancho fijo. Se
Hasta 2000 bytes en Hasta 2000 bytes en
rellena con espacios.
Oracle 8i. Oracle 9i.
Hasta 32767 bytes en Hasta 32767 bytes en
Donde tamaño es el número
PLSQL. PLSQL.
varchar2 de caracteres a almacenar.
(tamaño) Son cadenas de ancho
Hasta 4000 bytes en Hasta 4000 bytes en
variable.
Oracle 8i. Oracle 9i.
Son cadenas de ancho
long Hasta 2 gigabytes. Hasta 2 gigabytes.
variable.
Hasta 32767 bytes en Hasta 32767 bytes en
PLSQL. PLSQL.
Son cadenas binarias de ancho
raw
variable.
Hasta 2000 bytes en Hasta 2000 bytes en
Oracle 8i. Oracle 9i.
Son cadenas binarias de ancho
long raw Hasta 2 gigabytes. Hasta 2 gigabytes.
variable.
Una fecha entre el 1 Una fecha entre el 1
de Enero de 4712 A.C. de Enero de 4712 A.C.
date
y el 31 de Diciembre y el 31 de Diciembre
de 9999 D.C. de 9999 D.C.
5
fractional seconds
timestamp Incluye año, mes día, hora,
precision debe ser un
(fractional No soportado por minutos y segundos.
número entre 0 y 9.
seconds Oracle 8i.
(El valor por defecto
precision) Por ejemplo: timestamp(6)
es 6)
Incluye año, mes día, hora,
timestamp
fractional seconds minutos y segundos; con un
(fractional
precision debe ser un valor de desplazamiento de
seconds No soportado por
número entre 0 y 9. zona horaria.
precision) Oracle 8i.
(El valor por defecto
with time
es 6) Por ejemplo: timestamp(5)
zone
with time zone
Incluye año, mes día, hora,
timestamp
fractional seconds minutos y segundos; con una
(fractional
precision debe ser un zona horaria expresada como
seconds No soportado por
número entre 0 y 9. la zona horaria actual.
precision) Oracle 8i.
(El valor por defecto
with local
es 6) Por ejemplo: timestamp(4)
time zone
with local time zone
Período de tiempo
interval year precision debe
almacenado en años y meses.
year (year No soportado por ser un número entre 0
precision) Oracle 8i. y 9. (El valor por
Por ejemplo: interval year(4)
to month defecto es 2)
to month
day precision debe
ser un número entre 0
interval
y 9. (El valor por
day (day Incluye año, mes día, hora,
defecto es 2)
precision) minutos y segundos.
No soportado por
to second
Oracle 8i. fractional seconds
(fractional Por ejemplo: interval day(2) to
precision debe ser un
seconds second(6)
número entre 0 y 9.
precision)
(El valor por defecto
es 6)
El formato del campo El formato del campo
rowid es: rowid es:
BBBBBBB.RRRR.FFFFF BBBBBBB.RRRR.FFFFF
Datos binarios de ancho fijo.
donde BBBBBBB es el donde BBBBBBB es el
Cada registro de la base de
rowid bloque en el fichero bloque en el fichero
datos tiene una dirección
de la base de datos; de la base de datos;
física o rowid.
RRRR es la fila del RRRR es la fila del
bloque; FFFFF es el bloque; FFFFF es el
fichero de la base de fichero de la base de
datos. datos.
6
urowid Rowid universal. Donde
Hasta 2000 bytes. Hasta 2000 bytes.
[tamaño] tamaño es opcional.
Válido en PLSQL, este Válido en PLSQL, este
boolean tipo de datos no tipo de datos no
existe en Oracle 8i. existe en Oracle 9i.
Hasta 32767 bytes en Hasta 32767 bytes en Donde tamaño es el número
nchar
PLSQL. Hasta 2000 PLSQL. Hasta 2000 de caracteres a almacenar.
(tamaño)
bytes en Oracle 8i. bytes en Oracle 9i. Cadena NLS de ancho fijo.
Donde tamaño es el número
Hasta 32767 bytes en Hasta 32767 bytes en
nvarchar2 de caracteres a almacenar.
PLSQL. Hasta 4000 PLSQL. Hasta 4000
(tamaño) Cadena NLS de ancho
bytes en Oracle 8i. bytes en Oracle 9i.
variable.
Localizadores de archivo
apuntan a un objeto binario
bfile Hasta 4 gigabytes. Hasta 4 gigabytes.
de sólo lectura fuera de la
base de datos.
Localizadores LOB apuntan a
blob Hasta 4 gigabytes. Hasta 4 gigabytes. un gran objeto binario dentro
de la base de datos.
Localizadores LOB apuntan a
clob Hasta 4 gigabytes. Hasta 4 gigabytes. un gran objeto de caracteres
dentro de la base de datos.
Localizadores LOB apuntan a
un gran objeto NLS de
nclob Hasta 4 gigabytes. Hasta 4 gigabytes.
caracteres dentro de la base
de datos.
7
Operadores lógicos AND (y lógico)
NOT (negacion)
OR (o lógico)
Operador de
||
concatenación
IF (expresion) THEN
-- Instrucciones
ELSIF (expresion) THEN
-- Instrucciones
ELSE
-- Instrucciones
END IF;
Sentencia GOTO
PL/SQL dispone de la sentencia GOTO. La sentencia GOTO desvía el flujo de ejecución a una
determinada etiqueta.
En PL/SQL las etiquetas se indican del siguiente modo: << etiqueta >>
DECLARE
flag NUMBER;
BEGIN
flag :=1 ;
8
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 disposición 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
instrucción EXIT. Su sintaxis es la siguiente
LOOP
-- Instrucciones
IF (expresion) THEN
-- Instrucciones
EXIT;
END IF;
END LOOP;
El bucle FOR, se repite tanta veces como le indiquemos en los identificadores inicio y final.
-- Instrucciones
END LOOP;
9
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
mínimo de un bloque.
Bloques anónimos
Subprogramas
10
Estructura de un Bloque
Los bloques PL/SQL presentan una estructura específica compuesta de tres partes bien
diferenciadas:
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;
DECLARE
/*Parte declarativa*/
nombre_variable DATE;
BEGIN
/*Parte de ejecucion
* Este código asigna el valor de la columna
"nombre_columna"
* a la variable identificada por "nombre_variable"
*/
SELECT SYSDATE
INTO nombre_variable
FROM DUAL;
EXCEPTION
/*Parte de excepciones*/
WHEN OTHERS THEN
dbms_output.put_line('Se ha producido un error');
END;
11
A continuación vamos a ver cada una de estas secciones
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 ... Además para algunos tipos de datos (NUMBER
y VARCHAR) podemos especificar la longitud.
La cláusula CONSTANT indica la definición de una constante cuyo valor no puede ser
modificado. Se debe incluir la inicialización de la constante en su declaración.
La cláusula 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 inicialización puede incluir cualquier expresión legal de PL/SQL, que lógicamente
debe corresponder con el tipo del identificador definido.
Los tipos escalares incluyen los definidos en SQL más 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 operación lógica. VARCHAR es un sinónimo de
CHAR.
También es posible definir el tipo de una variable o constante, dependiendo del tipo
de otro identificador, mediante la utilización de las cláusulas %TYPE y %ROWTYPE.
Mediante la primera opción 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 variables utilizando cursores.
12
Ejemplos:
DECLARE
/* Se declara la variable de tipo VARCHAR2(15)
identificada por v_location y se le asigna
el valor "Granada"*/
BEGIN
/*Parte de ejecucion*/
EXCEPTION
/*Parte de excepciones*/
END;
13
Estructura de un subprograma:
BEGIN
/*Parte de ejecucion*/
EXCEPTION
/*Parte de excepciones*/
END;
14
Cursores en PL/SQL
Cursores implícitos. Este tipo de cursores se utiliza para operaciones SELECT INTO.
Se usan cuando la consulta devuelve un único registro.
Cursores explícitos. Son los cursores que son declarados y controlados por el
programador. Se utilizan cuando la consulta devuelve un conjunto de registros.
Ocasionalmente también se utilizan en consultas que devuelven un único registro
por razones de eficiencia. Son más rápidos.
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 implícitos no necesitan
declaración.
declare
cursor c_paises is
SELECT CO_PAIS, DESCRIPCION
FROM PAISES;
begin
/* Sentencias del bloque ...*/
end;
Para procesar instrucciones SELECT que devuelvan más de una fila, son necesarios cursores
explícitos combinados con un estructura de bloque.
Un cursor admite el uso de parámetros. Los parámetros deben declararse junto con el
cursor.
declare
cursor c_paises (p_continente IN VARCHAR2) is
SELECT CO_PAIS, DESCRIPCION
FROM PAISES
15
/* Sentencias del bloque ...*/
end;
Cursores Implícitos
Los cursores implícitos se utilizan para realizar consultas SELECT que devuelven un único
registro.
Deben tenerse en cuenta los siguientes puntos cuando se utilizan cursores implícitos:
declare
vdescripcion VARCHAR2(50);
begin
SELECT DESCRIPCION
INTO vdescripcion
from PAISES
WHERE CO_PAIS = 'ESP';
end;
Los cursores implicitos sólo pueden devolver una fila, por lo que pueden producirse
determinadas excepciones. Las más comunes que se pueden encontrar son no_data_found
y too_many_rows. La siguiente tabla explica brevemente estas excepciones.
Excepcion Explicacion
NO_DATA_FOUND 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 sólo es capaz de recuperar una fila , esta
excepcion detecta la existencia de más de una fila.
Los cursores explícitos se emplean para realizar consultas SELECT que pueden devolver
cero filas, o más de una fila.
Para trabajar con un cursor explicito necesitamos realizar las siguientes tareas:
1. Declarar el cursor.
2. Abrir el cursor con la instrucción OPEN.
3. Leer los datos del cursor con la instrucción FETCH.
4. Cerrar el cursor y liberar los recursos con la instrucción CLOSE.
CURSOR nombre_cursor IS
instrucción_SELECT
17
CURSOR nombre_cursor(param1 tipo1, ..., paramN tipoN) IS
instrucción_SELECT
OPEN nombre_cursor;
-- o bien ...
CLOSE nombre_cursor;
El siguiente ejemplo ilustra el trabajo con un cursor explícito. 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);
18
BEGIN
OPEN cpaises;
FETCH cpaises INTO co_pais,descripcion,continente;
CLOSE cpaises;
END;
DECLARE
CURSOR cpaises
IS
SELECT CO_PAIS, DESCRIPCION, CONTINENTE
FROM PAISES;
registro cpaises%ROWTYPE;
BEGIN
OPEN cpaises;
FETCH cpaises INTO registro;
CLOSE cpaises;
END;
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;
19
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 situación:
Atributo Antes de abrir Al abrir Durante la recuperación Al finalizar la recuperación Después de cerrar
%NOTFOUND ORA-1001 NULL FALSE TRUE ORA-1001
%FOUND ORA-1001 NULL TRUE FALSE ORA-1001
%ISOPEN FALSE TRUE TRUE TRUE FALSE
%ROWCOUNT ORA-1001 0 * ** ORA-1001
Vamos a ver varias formas de iterar a través de un cursor. La primera es utilizando un bucle
LOOP con una sentencia EXIT condicionada:
OPEN nombre_cursor;
LOOP
END LOOP;
CLOSE nombre_cursor;
20
21
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 instrucción FECTH aparece dos veces.
OPEN nombre_cursor;
WHILE nombre_cursor%FOUND
LOOP
END LOOP;
CLOSE nombre_cursor;
22
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 más corta ya que el cursor es
implicitamente se ejecutan las instrucciones OPEN, FECTH y CLOSE.
END LOOP;
BEGIN
FOR REG IN (SELECT * FROM PAISES)
LOOP
dbms_output.put_line(reg.descripcion);
END LOOP;
END;
23
Cursores de actualización
Los cursores de actualización se declaran igual que los cursores explícitos, añadiendo FOR
UPDATE al final de la sentencia select.
CURSOR nombre_cursor IS
instrucción_SELECT
FOR UPDATE
Para actualizar los datos del cursor hay que ejecutar una sentencia UPDATE especificando la
cláusula WHERE CURRENT OF <cursor_name>.
DECLARE
CURSOR cpaises IS
select CO_PAIS, DESCRIPCION, CONTINENTE
from paises
FOR UPDATE;
co_pais VARCHAR2(3);
descripcion VARCHAR2(50);
continente VARCHAR2(25);
BEGIN
OPEN cpaises;
FETCH cpaises INTO co_pais,descripcion,continente;
WHILE cpaises%found
LOOP
UPDATE PAISES
SET CONTINENTE = CONTINENTE || '.'
WHERE CURRENT OF cpaises;
END;
Cuando trabajamos con cursores de actualización debemos tener en cuenta las siguientes
consideraciones: