Professional Documents
Culture Documents
datos desde o cambiar datos en la base de datos. Sin embargo, SQL no se puede u
tilizar para implementar toda la lgica de negocios y la funcionalidad que el usua
rio final necesita en nuestras aplicaciones. Esto nos lleva a PL/SQL.
PL/SQL significa Procedural Language/Structured Query Language (una extensin de p
rogramacin estructurada sobre SQL). PL/SQL ofrece un conjunto de instrucciones cls
icos de la programacin estructurada (instruccin condicional IF, loops o iteracione
s, asignaciones), organizado dentro de bloques (lo que se explica ms adelante), q
ue complementan y amplan el alcance de SQL.
Sin duda que es posible crear aplicaciones sobre Oracle y SQL sin usar PL/SQL. S
in embargo, utilizar PL/SQL para realizar operaciones especficas de bases de dato
s, particularmente la ejecucin de sentencias SQL, ofrece varias ventajas, incluye
ndo una estrecha integracin con SQL, un mejor rendimiento a travs del trfico de red
reducido, y la portabilidad (los programas PL/SQL pueden correr en cualquier in
stancia de base de datos Oracle). Por lo tanto, el cdigo del front-end de muchas
aplicaciones ejecuta tanto sentencias SQL como bloques PL/SQL, para maximizar el
rendimiento al tiempo que mejora la capacidad de mantenimiento de las aplicacio
nes.
Construyendo bloques de programas PL/SQL
PL/SQL es un lenguaje estructurado con bloques. Un bloque PL/SQL es definido por
las palabras clave DECLARE, BEGIN, EXCEPTION, y END, que dividen el bloque en t
res secciones
1. Declarativa: sentencias que declaran variables, constantes y otros elementos
de cdigo, que despus pueden ser usados dentro del bloque
2. Ejecutable: sentencias que se ejecutan cuando se ejecuta el bloque
3. Manejo de excepciones: una seccin especialmente estructurada para atrapar y ma
nejar cualquier excepcin que se produzca durante la ejecucin de la seccin ejecutabl
e
Slo la seccin ejecutable es obligatoria. No es necesario que usted declare nada en
un bloque, ni que maneje las excepciones que se puedan lanzar.
Un bloque es en s mismo una sentencia ejecutable, por lo que se pueden anidar los
bloques unos dentro de otros.
Aqu hay algunos ejemplos:
El clsico Hola Mundo! es un bloque con una seccin ejecutable que llama al procedimien
to DBMS_OUTPUT.PUT_LINE para mostrar texto en pantalla:
BEGIN
DBMS_OUTPUT.put_line('Hola Mundo!');
END;
Las funciones y procedimientos tipos de bloques con un nombre son discutidos con m
ayor detalle ms adelante en este artculo, as como los paquetes. En pocas palabras,
sin embargo, un paquete es un contenedor de mltiples funciones y procedimientos.
Oracle extiende PL/SQL con muchos paquetes incorporados en el lenguaje.
El siguiente bloque declara una variable de tipo VARCHAR2 (un string) con un lar
go mximo de 100 bytes para contener el string Hola Mundo! . Despus, el procedimiento D
BMS_OUTPUT.PUT_LINE acepta la variable, en lugar del literal, para desplegarlo:
DECLARE
l_mensaje VARCHAR2(100) := 'Hola Mundo!';
BEGIN
DBMS_OUTPUT.put_line(l_mensaje);
END;
Note que he llamado a la variable l_mensaje. Normalmente uso el prefijo l_ para
variables locales variables definidas dentro del cdigo de un bloque y el prefijo g_
para variables globales definidas en un paquete.
El siguiente ejemplo de bloque agrega una seccin de manejo de excepciones que atr
apa cualquier excepcin (WHEN OTHERS) que pueda ser lanzada y muestra el mensaje d
e error, que es retornado por la funcin SQLERRM (provista por Oracle).
DECLARE
l_mensaje VARCHAR2(100) := 'Hola Mundo!';
BEGIN
DBMS_OUTPUT.put_line(l_mensaje);
EXCEPTION
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line(SQLERRM);
END;
El siguiente ejemplo de bloque demuestra la habilidad de PL/SQL de anidar bloque
s dentro de bloques as como el uso del operador de concatenacin (||) para unir mlti
ples strings.
DECLARE
l_mensaje VARCHAR2(100) := 'Hola';
BEGIN
DECLARE
l_mensaje2 VARCHAR2(100) := l_mensaje || ' Mundo!';
BEGIN
DBMS_OUTPUT.put_line(l_mensaje2);
END;
EXCEPTION
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line(DBMS_UTILITY.format_error_stack);
END;
Ejecutando bloques PL/SQL
Una vez que hemos escrito un bloque de cdigo PL/SQL ste se puede ejecutar. Existen
muchas herramientas para ejecutar cdigo PL/SQL. La ms bsica es SQL*Plus, una inter
faz de lnea de comandos para ejecutar sentencias SQL as como bloques PL/SQL. La Fi
gura 1 muestra un ejemplo de ejecucin del ms simple de los bloques de ejemplo de n
uestro Hola Mundo! en SQL*Plus.
Ejecutando bloques PL/SQL
Figura 1: Ejecutando Hola Mundo!
en SQL*Plus
PL/SQL D
Cada herramienta ofrece, con algunas diferencias, ventanas y pasos para crear, g
uardar, y ejecutar bloques PL/SQL, as como habilitar y deshabilitar la salida del
servidor. En esta serie de artculos, voy a suponer que slo tienen acceso a SQL*Pl
us y que van a ejecutar todas las sentencias en una ventana de comandos SQL*Plus
.
Pngale nombre a los bloques!
Todos los bloques que hemos visto hasta el momento son annimos , no tienen nombres.
Si los bloques annimos fueran la nica manera de organizar el cdigo, sera muy difcil u
sar PL/SQL para crear una aplicacin grande y compleja. Por esto, PL/SQL soporta l
a definicin de bloques nombrados (named blocks), tambin conocidos como subprograma
s. Los subprogramas pueden ser procedimientos o funciones. Generalmente, un proc
edimiento se utiliza para realizar una accin y una funcin se utiliza para calcular
y devolver un valor. Voy a tratar sobre subprogramas con mucho ms detalle en un
prximo artculo de esta serie. Por ahora, vamos a asegurarnos de que se comprendan
los conceptos bsicos detrs de la creacin del subprograma.
Supongamos que necesitamos mostrar "Hola Mundo!" desde mltiples lugares en nuestra
aplicacin. Queremos evitar la repeticin de la misma lgica en todos esos lugares. P
or ejemplo, qu pasa cuando tenemos que cambiar el mensaje, tal vez para "Hola Unive
rso!"? Vamos a tener que encontrar todos los lugares en nuestro cdigo donde esta
lgica aparece.
En su lugar, vamos a crear un procedimiento denominado hola_mundo mediante la ej
ecucin de la siguiente sentencia DDL (Data Definition Language):
CREATE OR REPLACE PROCEDURE hola_mundo IS
l_mensaje VARCHAR2(100) := 'Hola Mundo!';
BEGIN
DBMS_OUTPUT.put_line(l_mensaje);
END hola_mundo;
Con esto hemos extendido PL/SQL. Adems de llamar a los programas creados por Orac
le e instalados en la base de datos (como DBMS_OUTPUT.PUT_LINE), podemos llamar
a nuestro propio subprograma dentro de un bloque PL/SQL:
BEGIN
hola_mundo;
END;
Hemos escondido todos los detalles de cmo decir hola al mundo dentro del cuerpo (
body), o implementacin, de nuestro procedimiento. Ahora podemos llamar a este pro
cedimiento hola_mundo y mostrar el mensaje deseado sin tener que escribir la lla
mada a DBMS_OUTPUT.PUT_LINE o averiguar la forma correcta de darle formato al te
xto. Podemos llamar a este procedimiento desde cualquier lugar en nuestra aplica
cin. As que si alguna vez necesitamos cambiar ese texto, lo vamos a hacer en un so
lo lugar, el nico punto de definicin de ese texto.
El procedimiento hola_mundo es muy simple. Tus procedimientos tendrn mucho ms cdigo
, y casi siempre tambin tendrn parmetros. Los parmetros pasan informacin a los subpro
gramas, cuando stos son llamados, y es lo que permite crear subprogramas ms flexib
les y genricos. Se pueden usar en muchos contextos diferentes.
He mencionado antes que algn da puede ser que desee mostrar "Hola Universo!" en lug
ar de "Hola Mundo!". Podra hacer una copia de nuestro procedimiento hola_mundo y c
ambiar el texto que se muestra:
CREATE OR REPLACE PROCEDURE hola_universo IS
l_mensaje VARCHAR2(100) := 'Hola Universo!';
BEGIN
DBMS_OUTPUT.put_line(l_mensaje);
END hola_universo;
Podramos, sin embargo, terminar con las decenas de variantes del mismo procedimient
o hola, que hara muy difcil mantener nuestra aplicacin. Un enfoque mucho mejor es a
nalizar el procedimiento e identificar qu partes se mantienen incambiadas (son es
tticas) cuando el mensaje tiene que cambiar y qu partes cambian. Luego podemos pas
ar las partes que cambian como parmetros y tener un procedimiento nico que se pued
e utilizar en diferentes circunstancias.
As que vamos a cambiar hola_mundo (y hola_universo) a un nuevo procedimiento, hol
a_lugar:
CREATE OR REPLACE PROCEDURE hola_lugar (lugar_in IN VARCHAR2) IS
l_mensaje VARCHAR2(100);
BEGIN
l_mensaje := 'Hola ' || place_in;
DBMS_OUTPUT.put_line(l_mensaje);
END hola_lugar;
Justo despus del nombre del procedimiento, aadimos entre parntesis de apertura y ci
erre, un nico parmetro. Podemos tener varios parmetros, pero cada parmetro de la mis
ma forma bsica:
nombre_de_parametro
modo_de_parametro
tipo_de_datos
e hablar sobre las reglas para los nombres (o, para ser ms precisos, identificado
res) tanto en PL/SQL como, de forma ms general, en una base Oracle.
Estas son las reglas para construir identificadores vlidos en una base Oracle:
El largo mximo es de 30 caracteres.
El primer caracter debe ser una letra, pero cada caracter despus del primero pued
e ser una letra, un nmero (0 a 9), un signo de pesos ($), un guin bajo (_), o un n
umeral (#). Todos los siguientes son identificadores vlidos:
hola_mundo
hola$mundo
hola#mundo
pero estos son invlidos:
1hola_mundo
hola%mundo
PL/SQL es case-insensitive (no es sensitivo a maysculas y minsculas) con respecto
a los identificadores. PL/SQL trata todos los siguientes como el mismo identific
ador:
hola_mundo
Hola_Mundo
HOLA_MUNDO
Para ofrecer ms flexibilidad, Oracle permite evitar las restricciones de la segun
da y tercera regla, encerrando al identificador entre comillas dobles. Un quoted
identifier (identificador encerrado entre comillas) puede contener cualquier se
cuencia de caracteres imprimibles excluyendo las comillas dobles; las diferencia
s entre maysculas y minsculas sern adems preservadas. As, todos los siguientes identi
ficadores son vlidos y distintos:
"Abc"
"ABC"
"a b c"
Es muy raro encontrar identificadores entre comillas en cdigo PL/SQL; algunos gru
pos de desarrollo los usan para conformar con sus convenciones de nombres o porq
ue encuentran que una mezcla de maysculas y minsculas resulta ms fcil de leer.
Estas mismas reglas aplican a los nombres de los objetos de base de datos como t
ablas, vistas y procedimientos, con una regla adicional: a menos que se encierre
n entre comillas los nombres de estos objetos, Oracle los mantendr en maysculas.
As que cuando creamos un procedimiento como el que sigue:
CREATE OR REPLACE PROCEDURE hola_mundo IS
BEGIN
DBMS_OUTPUT.put_line('Hola Mundo!');
END hola_mundo;
la base de datos Oracle lo mantendr con el nombre HOLA_MUNDO.
En el bloque siguiente, llamaremos este procedimiento tres veces, y aunque el no
mbre luzca diferente cada vez, siempre se ejecutar el mismo procedimiento:
BEGIN
hola_mundo;
HOLA_MUNDO;
"HOLA_MUNDO";
END;
Por otro lado, la base Oracle no ser capaz de ejecutar el procedimiento si lo lla
mamos como sigue:
BEGIN
"hola_mundo";
END;
Esto buscar dentro de la base un procedimiento llamado hola_mundo en lugar de HOL
A_MUNDO.
Si no se quiere que los nombres de los subprogramas se mantengan en maysculas, lo
s nombres se deben encerrar entre comillas cuando se crea el subprograma:
CREATE OR REPLACE PROCEDURE "Hola_Mundo" IS
BEGIN
DBMS_OUTPUT.put_line('Hola Mundo!');
END "Hola_Mundo";
Ejecutando SQL dentro de bloques PL/SQL
PL/SQL es un lenguaje de programacin de base de datos. Casi todos los programas q
ue escribiremos en PL/SQL leern desde, o escribirn en, una base de datos Oracle ut
ilizando SQL. Aunque estas series asumen que se conoce SQL, debemos estar consci
entes de la forma en que llamamos a las sentencias desde un bloque PL/SQL.
Y
r
s
l
aqu hay algunas buenas noticias: Oracle hace que sea muy fcil escribir y ejecuta
sentencias SQL en PL/SQL. La mayor parte de las veces, simplemente escribiremo
las sentencias SQL directamente en nuestro bloque PL/SQL y despus agregaremos e
cdigo necesario para la interfaz entre las sentencias SQL y el cdigo PL/SQL.
Supongamos, por ejemplo, que tenemos una tabla llamada empleados, con una column
a clave primaria id_empleado, y una columna apellido. Podemos ver el apellido de
l empleado con ID 138, como sigue:
SELECT apellido
FROM empleados
WHERE id_empleado = 138
Ahora querramos ejecutar esta misma consulta dentro de nuestro bloque PL/SQL y de
splegar el nombre. Para hacer esto, necesitaremos copiar el apellido desde la tabl
a a una variable local, lo cual podemos hacer con la clusula INTO:
DECLARE
v_apellido empleados.apellido%TYPE;
BEGIN
SELECT apellido
INTO v_apellido
FROM empleados
WHERE id_empleado = 138;
DBMS_OUTPUT.put_line(v_apellido);
END;
Primero declaramos una variable local, y haciendo esto introducimos otra caracte
rstica elegante de PL/SQL: la capacidad de fijar el tipo de datos de nuestra vari
able en funcin del tipo de datos de una columna en una tabla (esto ser profundizad