El documento proporciona una introducción a PL/SQL, incluyendo una descripción de sus funciones integradas como SYSDATE, NVL y DECODE. También describe cursores implícitos y explícitos, y cómo se usan en PL/SQL. Finalmente, explica el manejo de excepciones en PL/SQL, distinguiento entre excepciones predefinidas como NO_DATA_FOUND y excepciones definidas por el usuario.
2. Lic. ClaudiaCuellar
1ORACLE PL/SQL
F u n d a m e n t o s d e P L / S Q L
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.
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
versatilidadde loslenguajesde programacióntradicionales.PL/SQLes el lenguaje de programación que
proporciona Oracle para extender el SQL estándar con otro tipo de instrucciones.
F u n c i o n e s i n t e g r a d a s d e P L / S Q L
PL/SQL tiene ungrannúmerode funciones incorporadas,sumamente útiles.A continuaciónvamosaver
algunasde las másutilizadas.
SYSDATE Devuelve lafechadel sistema:
SELECT SYSDATE FROM DUAL;
NVL Devuelveel valorrecibidocomoparámetroenel casode que expresiónseaNULL, o expresiónen
caso contrario.
NVL(<expresión>, <valor>)
El siguienteejemplodevuelve0si el precioesnulo,yel preciocuandoestá informado:
SELECT CO_PRODUCTO, NVL(PRECIO, 0) FROM PRECIOS;
DECODE Decode proporcionalafuncionalidadde unasentenciade control de flujo if-elseif-else.
DECODE(<expr>, <cond1>, <val1>[, ..., <condN>, <valN>], <default>)
Esta funciónevalúaunaexpresión"<expr>",si se cumple laprimeracondición"<cond1>"devuelveel
valor1 "<val1>", encaso contrarioevalúala siguientecondicióny así hastaque una de lascondicionesse
cumpla.Si no se cumple ningunacondiciónse devuelve el valorpordefecto.
Es muycomún escribirlafunciónDECODEidentadacomosi se tratase de un bloque IF.
3. Lic. ClaudiaCuellar
2ORACLE PL/SQL
SELECT DECODE (co_pais, /* Expresion a evaluar */
'ESP', 'ESPAÑA', /* Si co_pais = 'ESP' ==> 'ESPAÑA' */
'MEX', 'MEXICO', /* Si co_pais = 'MEX' ==> 'MEXICO' */
'PAIS '||co_pais)/* ELSE ==> concatena */
FROM PAISES;
TO_DATE Convierte unaexpresiónal tipofecha.El parámetroopcional formatoindicael formatode
entradade la expresiónnoel de salida.
TO_DATE(<expresión>, [<formato>])
En este ejemploconvertimoslaexpresión '01/12/2006' de tipoCHAR a una fecha(tipoDATE).Conel
parámetroformatole indicamosque lafechaestáescritacomo día-mes-añoparaque devuelve el unode
diciembre ynoel doce de enero.
SELECT TO_DATE('01/12/2006',
'DD/MM/YYYY')
FROM DUAL;
Este otro ejemplomuestralaconversiónconformatode día y hora.
SELECT TO_DATE('31/12/2006 23:59:59',
'DD/MM/YYYY HH24:MI:SS')
FROM DUAL;
TO_CHAR Convierte unaexpresiónal tipoCHAR. El parámetroopcional formatoindica el formato
de salidade la expresión.
TO_CHAR(<expresión>, [<formato>])
SELECT TO_CHAR(SYSDATE, 'DD/MM/YYYYY')
FROM DUAL;
TO_NUMBER Convierte unaexpresiónalfanuméricaennumérica.Opcionalmente podemosespecificar
el formatode salida.
TO_NUMBER(<expresión>, [<formato>])
SELECT TO_NUMBER ('10')
FROM DUAL;
TRUNC Trunca una fechao número.
Si el parámetrorecibidoesunafecha eliminalashoras,minutosysegundosde lamisma.
4. Lic. ClaudiaCuellar
3ORACLE PL/SQL
SELECT TRUNC(SYSDATE)FROM DUAL;
Si el parámetroesun númerodevuelve laparte entera.
SELECT TRUNC(9.99)FROM DUAL;
LENGTH Devuelve lalongitudde untipoCHAR.
SELECT LENGTH('HOLA MUNDO')FROM DUAL;
INSTR Busca una cadenade caracteresdentrode otra. Devuelvelaposiciónde la ocurrenciade la
cadenabuscada.
Su sintaxiseslasiguiente:
INSTR(<char>, <search_string>, <startpos>, <occurrence> )
SELECT INSTR('AQUI ES DONDE SE BUSCA', 'BUSCA', 1, 1 )
FROM DUAL;
REPLACE Reemplazauntextoporotroenun expresiónde búsqueda.
REPLACE(<expresión>, <búsqueda>, <reemplazo>)
El siguienteejemploreemplazalapalabra'HOLA' por 'VAYA'en lacadena 'HOLA MUNDO'.
SELECT REPLACE ('HOLA MUNDO','HOLA', 'VAYA')-- devuelve VAYA
MUNDO
FROM DUAL;
SUBSTR Obtiene unaparte de una expresión,desdeunaposiciónde iniciohastaunadeterminada
longitud.
SUBSTR(<expresión>, <posicion_ini>, <longitud> )
SELECT SUBSTR('HOLA MUNDO', 6, 5) -- Devuelve MUNDO
FROM DUAL;
UPPER Convierte unaexpresión alfanuméricaamayúsculas.
SELECT UPPER('hola mundo') -- Devuelve HOLA MUNDO
FROM DUAL;
5. Lic. ClaudiaCuellar
4ORACLE PL/SQL
LOWER Convierte unaexpresiónalfanuméricaaminúsculas.
SELECT LOWER('HOLA MUNDO') -- Devuelve hola mundo
FROM DUAL;
ROWIDTOCHAR Convierte unROWIDa tipocarácter.
SELECT ROWIDTOCHAR(ROWID)
FROM DUAL;
RPAD Añade N vecesunadeterminadacadenade caracteresa laderechauna expresión.Muyútil para
generarficherosde textode anchofijo.
RPAD(<expresión>, <longitud>, <pad_string> )
El siguiente ejemploañade puntosalaexpresión'Holamundo'hastaalcanzaruna longitudde 50
caracteres.
SELECT RPAD('Hola Mundo', 50, '.')
FROM DUAL;
LPAD Añade N vecesunadeterminadacadenade caracteresa laizquierdade unaexpresión.Muyutil
para generarficherosde textode anchofijo.
LPAD(<expresión>, <longitud>, <pad_string> )
El siguienteejemploañade puntosalaexpresión'Holamundo'hastaalcanzaruna longitudde 50
caracteres.
SELECT LPAD('Hola Mundo', 50, '.')
FROM DUAL;
RTRIM Eliminalosespaciosenblancoala derechade una expresión
SELECT RTRIM ('Hola Mundo ')
FROM DUAL;
LTRIM Eliminalosespaciosenblancoala izquierdade unaexpresión
SELECT LTRIM (' Hola Mundo')
FROM DUAL;
6. Lic. ClaudiaCuellar
5ORACLE PL/SQL
TRIM Eliminalosespaciosenblancoala izquierdayderechade una expresión
SELECT TRIM (' Hola Mundo ')
FROM DUAL;
MOD Devuelveel restode ladivisiónenteraentre dosnúmeros.
MOD(<dividendo>, <divisor> )
SELECT MOD(20,15) -- Devuelve el módulo de dividir 20/15
FROM DUAL
C U R S O R E S E N P L / S Q L
PL/SQL utiliza cursores para gestionar las instrucciones SELECT. Un cursor es un conjunto de registros
devuelto por una instrucción SQL. Técnicamente los cursores son fragmentos de memoria que
reservados para procesar los resultados de una consulta SELECT.
Podemos distinguir dos tipos de cursores:
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
utilizanenconsultasque devuelvenunúnicoregistroporrazonesde eficiencia.Sonmásrápidos.
Un cursor se define comocualquierotravariable de PL/SQL y debe nombrarse de acuerdo a los mismos
convenios que cualquier otra variable.
Los cursoresimplícitosse utilizanpararealizarconsultasSELECTque devuelvenunúnico registro. Deben
tenerse en cuenta los siguientes puntos cuando se utilizan cursores implícitos:
Los cursores implícitos no deben ser declarados
Con cada cursor implícito debe existir la palabra clave INTO.
Las variablesque recibenlosdatosdevueltosporel cursortienen que contenerel mismotipo de
dato que las columnas de la tabla.
Los cursoresimplícitossolopueden devolver una única fila. En caso de que se devuelva más de
una fila (o ninguna fila) se producirá una excepción. Las más comunes son:
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_ROWSDado que cada cursor implícitosólo es capaz de recuperar una fila, esta
excepción detecta la existencia de más de una fila.
7. Lic. ClaudiaCuellar
6ORACLE PL/SQL
El siguiente ejemplo declara un cursor explícito:
Para procesar instrucciones SELECT que devuelvan más de una fila, son necesarios cursores explícitos
combinados con una estructura de bloque.
Cursor FOR …. LOOP
El trabajo normal de un cursor consiste en declarar un cursor, declarar una variable que recogerá los
datos del cursor, abrir el cursor, recuperar con fetch, una a una, las filas extraídas introduciendo los
datos en las variables, procesándolos y comprobando si se han recuperado datos o no.
Para resumir todas esas tareas, tenemos una estructura cursor FOR...LOOP que hace todas estas cosas
de forma implícita, todas menos la declaración del cursor.
El formato y el uso de esta estructura es:
1. Se declara la información cursor en la sección correspondiente
2. Se presentael cursorutilizandoel siguiente formato:FORnombreVarRegIN nombreCursorLOOP
…. END LOOP;
Al entrar en el bucle se abre el cursor de manera automática, se declara implícitamente la variable
nombreVarRegde tipo nombrecursor%ROWTYPE y se ejecuta el primer fetch cuyo resultado quedarán
ennombreVarReg.A continuaciónse realizaranlasaccionesque correspondashastallegar al END LOOP.
Este es un ejemplodel LOOP ….ENDLOOP:
DECLARE
cursor c2 is select nombre, peso, estatura from jugador where salario>1200;
BEGIN
FOR vreg IN c2 LOOP
DBMS_OUTPUT.PUT_LINE (vreg.nombre || '-' ||vreg.peso || '-' ||
vreg.estatura);
END LOOP;
END;
Cursorescon Parámetros
Un cursor admite el usode parámetros.Losparámetrosdebendeclararse juntoconel cursor.
declare
cursor c_paises is
SELECT CO_PAIS, DESCRIPCION
FROM PAISES;
begin
/* Sentencias del bloque ...*/
end;
8. Lic. ClaudiaCuellar
7ORACLE PL/SQL
El siguiente ejemplo muestra la declaración de un cursor con un parámetro, identificado por
p_continente.
E X C E P C I O N E S O R A C L E
Las excepciones,presentesenlamayoríade loslenguajesde programación,sirvenparatratar errores en
tiempode ejecución.Enel sistemaque nosocupa,Oracle,sirventambiénparadefinir qué se debe hacer
frente aerroresen sentenciasdefinidas por el usuario. Cuando se produce un error PL/SQL levanta una
excepción y pasa el control a la sección excepción correspondiente al bloque PL/SQL.
El formatosería el siguiente:
BEGIN
.........
......
......
EXCEPTION
WHEN <nombre_excepción> THEN
<instrucciones>;
......
[WHEN OTHERS THEN <instrucciones>;]
END;
Excepcionespredefinidas
Son aquellas que se disparan automáticamente al producirse determinados errores. Estas son las más
comunes:
NOMBRE DE LA EXCEPCION NUMERO DE
ERROR
DESCRIPCION
NO_DATA_FOUND ORA-01403 Se produce cuando un select into no devuelve ninguna fila.
TOO_MANY_ROWS ORA-01422 Se produce cuando select into devuelve más de una fila.
INVALID_CURSOR ORA-01001 Se realizó una operación ilegal sobre un cursor
ZERO_DIVIDE ORA-01476 Se puede cuando hay una división entre 0.
DUP_VAL_ON_INDEX ORA-00001 Se crea cuando se intenta almacenar un valor que crearía
duplicados en la clave primaria o en una columna con
restricción UNIQUE.
INVALID_NUMBER ORA-01722 Se produce cuando se intenta convertir una cadena a un
valor numérico.
declare
cursor c_paises (p_continente IN VARCHAR2) is
SELECT CO_PAIS, DESCRIPCION
FROM PAISES
WHERE CONTINENTE = p_continente;
begin
/* Sentencias del bloque ...*/
end;
9. Lic. ClaudiaCuellar
8ORACLE PL/SQL
Hay alguna más pero estas son las más utilizadas y tenemos que tener en cuenta que no es necesario
declararlas en la sección DECLARE.
BEGIN
select
......
......
EXCEPTION
WHEN NO_DATA_FOUND THEN
<instrucciones>;
DB_OUTPUT.PUT.LINE(‘Expresion NO_DATA_FOUND’);
WHEN TOO_MANY_ROWS THEN
<instrucciones>;
......
[WHEN OTHERS THEN <instrucciones>;]
END;
Excepcionesdefinidasporel usuario
Son aquellasque creael usuario.Paraellose requierentrespasos:
1. Definición: se realiza en la zona de DECLARE con el siguiente formato: nombre_excepción
EXCEPTION
LOGIN_DENIED ORA-01017 Error cuando intentamos conectarnos a Oraclecon un login
y clave no válidos.
NOT_LOGGER_ON ORA-01012 Se produce cuando intentamos acceder a la base de datos
sin estar conectados.
PROGRAM_ERROR ORA-06501 Se produce cuando hay un problema interno en la
ejecución del programa.
ACCESS_INTO_NULL ORA-06530 Se intentan asignar valores a un objeto que no se había
inicializado.
CASE_NOT_FOUND ORA-06592 Ninguna opción WHEN dentro de la instrucción CASE
captura el valor, y no hay instrucción ELSE
COLLECTION_IS_NULL ORA-06531 Se intenta utilizar un varray o una tabla anidada que no
estaba inicializada
CURSOR_ALREADY_OPEN ORA-06511 Se intenta abrir un cursor que ya se había abierto
ROWTYPE_MISMATCH ORA-06504 Hay incompatibilidad detipos entre el cursor y las variables
a las que se intentan asignar sus valores
STORAGE_ERROR ORA-06500 No hay memoria suficiente
SUBSCRIPT_BEYOND_COUNT ORA-06533 Se hace referencia a un elemento de un varray o una tabla
anidada usando un índice mayor que los elementos que
poseen
SUBSCRIPT_OUTSIDE_LIMIT ORA-06532 Se hace referencia a un elemento de un varray o una tabla
anidada usando un índice cuyo valor está fuera del rango
legal
SYS_INVALID_ROWID ORA-01410 Se convierte un texto en un número de identificación de
fila (ROWID) y el texto no es válido
TIMEOUT_ON_RESOURCE ORA-00051 Se consumió el máximo tiempo en el que Oracle permite
esperar al recurso
VALUE_ERROR ORA-06502 Hay un error aritmético, de conversión, de redondeo o de
tamaño en una operación
10. Lic. ClaudiaCuellar
9ORACLE PL/SQL
2. Disparar o levantar la excepción mediante la orden raise: RAISE ;
3. Tratar la excepción en el apartado EXCEPTION: WHEN THEN ;
El formatosería el siguiente:
DECLARE
...
Importe_mal EXCEPTION;
...
BEGIN
...
IF precio NOT BETWEEN mínimo and máximo THEN
RAISE importe_mal;
END IF;
...
EXCEPTION
WHEN importe_mal THEN
DBMS_OUTPUT.PUT_LINE("Importe incorrecto");
...
END;
Otras excepciones
Existenotroserroresinternosde Oracle que notienenasignadaunaexcepción,sinouncódigo de error y
un mensaje, a los que se accede mediante funciones.
Funciones para Identificar Excepciones
SQLCODE
Devuelve el valornuméricodel códigode errorSQL.No se puede referenciar directamente, hay
que asignarlo a una variable PL/SQL de tipo NUMBER.
Valor de
SQLCODE
DESCRIPCION
0 No se encontró ninguna excepción
1 Excepción definida por el usuario
+100 Excepción NO_DATA_FOUND
negativo Otro número de error del Servidor Oracle
SQLERRM
Devuelve el mensaje asociado con el número de error. Tipo VARCHAR2.
Cuandose produce un error de estosse trasfiere directamente el control alasecciónEXCEPTION donde
se tratara el error enla cláusula WHEN OTHERS de la siguienteforma:
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error'||SQLCODE||SQLERRM.)
DECLARE
err_num NUMBER;
err_msg VARCHAR2(255);
result NUMBER;
BEGIN
SELECT 1/0 INTO result
FROM DUAL;
EXCEPTION
11. Lic. ClaudiaCuellar
10ORACLE PL/SQL
Utilizaciónde RAISE_APPLICATION_ERROR
En el paquete DBMS_STANDARDse incluye unprocedimiento llamado RAISE_APPLICATION_ERROR que
nos sirve para levantar errores y definir mensajes de error. Su formato es el siguiente:
RAISE_APPLICATION_ERROR(numero_error,mensaje_error);
Es importante saberque el númerode errorestácomprendidoentre -20000 y -20999 y el mensaje es
una cadenade caracteres de hasta 512 bytes.
Este procedimientocreaunaexcepciónque solopuede sertratadaenWHEN OTHERS.
Ponemosunejemploparaque nosquede másclaro.
CREATE or REPLACE PROCEDURE subir_horas (emple NUMBER, horas_subir NUMBER)
IS
horas_actuales NUMBER;
BEGIN
Select horas into horas_actuales from empleados where id_empleado=emple;
if horas_actuales is NULL then
RAISE_APPLICATION_ERROR(-20010,'No tiene horas');
else
update empleados set horas=horas_actuales + horas_subir where
id_empleado=emple;
end if;
End subir_horas;