Вы находитесь на странице: 1из 36

c  

 

V   
V 
 
V 

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

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

½ 

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


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

denominada bloque.

Un bloque tiene 3 zonas:

^ donde se declaran objectos locales. Suele ir precedida por la

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

     !"#

^ es una zona opcional precedida por la cláusula EXCEPTION, donde

se gestionan las excepciones.

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

ÿ 



 



 

 

ÿ

  
!
 

"

Las únicas cláusulas obligatorias son BEGIN y END

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

ventana de Sql *PLUS

set serveroutput on;

ejemplo de un bloque


#$%$ %!  %& '()"



    !  #  '**+,! # ,+ )"

!  %!    !$-** ./  !$-(0"

#$%$ %! 1-23456"

  7 %  !  ./  !$-(0

82$6696$ '#$%$ %!  :: ,%! 


%&  ! # ,)"

 
   
  
 

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

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

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



%& $#  & !  "



999

Un ejemplo seria este:



!
 68';+()"

% 68'() <6 0"

!  ='(0)  6 1-, %  ,"

 
!
 >=('?@)"



9999

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

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



%& %! 9%& 4A"

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

variable. Esto lo hacemos con el atributo %ROWTYPE




%7 %! 45A"

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

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

à
  
  

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

lenguaje de programación.

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

repetitivas (WHILE, FOR, LOOP)

La estructura del IF seria la siguiente:

< 

 =

 

 

2< 

 =

 

 

9999

2

 

 

 <"

La estructura del WHILE seria la siguiente:

5= 

 

 

 

 "

La estructura del FOR se escribiría así:

< #  &   %B% %C % 

 

 

 

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

seria la siguiente:
< #  &   >2

7 9999999
 

 

 

99999

 "

Y la estructura del LOOP seria de esta forma:



 

 

9999

 5= 



 

 

999

 "

› 


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

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

sino que se guarda en un área de memoria a la que se accede mediante los nombrados
cursores. Para realizar una consulta en PL/SQL tenemos que guardar el resultado en

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

este:


 
 % D  #  & D 7 %  &  ÿ./ 



'E)  #% 7 % #  "

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

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

£  

 

Las excepciones sirven para tratar los errores y mensajes. Oracle tiene una serie de
excepciones que son las más frecuentes y con las que la mayoría de la gente trabaja.

Unas de las más usadas son:

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


TOO_MANY_ROWS (cuando una orden tipo select ha devuelto mas de una fila)
OTHERS THEN RAISE_APPLICATION_ERROR (para cualquier otro tipo de error desconocido)

Un ejemplo seria el siguiente:




# !  #
/ '?0)"

#7
 #
/ '(0)"




 ! +7
  # ! +#7
 7 % %! ./ %!-?@"

82$6696$ '# ! ::1 F :: #7


)"



5= $$<6 =     %! #  ', / G  ,)"

5= $8A$52 =     %! #   ', %    ,)"

5= = = 2$$'F(000+,   ! 



,)"

"

à
   

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

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

que hemos ido viendo hasta ahora.

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


6 %& $! 
% 

ÿ'   ! C%  )

2

ÿ

 



 

 "

ÿ2


!
 "

"

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

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

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

devolver valores.

Si subís varias lineas y veis el ejemplo de control de excepciones, podéis ver que hemos
utilizado un atributo como DBMS_OUTPUT. Bien pues esto lo que nos permite es visualizar en
pantalla los resultados, tanto excepciones como mensajes. Lo utilizamos porque PL/SQL no
dispone de ordenes o sentencias que capturen datos introducidos por teclado, ni tampoco

para visualizar datos en pantalla.

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


correctamente tenemos que poner el SET SERVEROUTPUT a ON

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

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

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

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

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


<comentario> */´

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

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

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

posteriormente. Para ello ejecutamos la siguiente sentencia:

 # %& 7
/ 

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

ejecutar la siguiente sentencia:

  %& 7
/ 

Una vez cargado el fichero ejecutamos el bloque con la sentencia run nombrefichero.
O podemos hacer los dos pasos con una sola sentencia: start nombrefichero

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

almacena automáticamente en la base de datos y para ejecutarlo tan solo tenemos que
realizar la siguiente operación:


 %& $! 
% '! C%  )"

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

pero de una forma mas exhaustiva.


½  

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


suelen crear y ejecutar desde PL/SQL.

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

lo podemos ejecutar con la orden ³run´. También podemos guardarlo en un fichero con la
siguiente orden:

save nombrefichero [replace]

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

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

orden:

start nombrefichero

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

Pero también podemos cargarlo sin ejecutarlo con la orden ³get´ y luego ejecutarlo

posteriormente con la orden ³run´

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



82$6696$',%& ,)"

"

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

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

antepuestas del & para que funcionen.

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



>%
  9%& 4A"




 %&  >% 7 %
   ./ <- ,H>$7,"

82$6696$ '>%)"
"

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

o funciones.


  
 

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

bloques anónimos que se almacenaban en el buffer.

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

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

almacenan en la propia base de datos.

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

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

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


parte añadiendo al principio la siguiente secuencia ³CREATE OR REPLACE´ para crearlo, o

modificarlo si ya existe.

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

   6 # $ '% >=()

2

< >=('?0)"

% >=('?0)"




 7+ %
   <+% 7 %   ./ %& -%"

82$6696$',%& 1,::%:: ,<1, ::<:: ,%


 , ::%)"



5= $$<6 =

82$6696$', / % 
    :: %)"

"

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

con errores de compilación´. Para ver estos errores tenemos la orden SHOW ERRORS.
Al tener almacenado el procedimiento en la base de datos, este puede ser llamado por
cualquier usuario que tenga los permisos oportunos. Para invocar un procedimiento

utilizamos la orden EXECUTE

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

EXECUTE ver_usuario('Luis');

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



# $ ',,)"

"

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

siguiente forma:

- - para comentar en una sola linea

/* <comentario>*/ para varias lineas.

ë  

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

además se han incorporado algunos nuevos:

á| char(n): almacena una cantidad fija de caracteres

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

á| long(n): almacena cadenas de longitud variable

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


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

á| date: almacena fechas completas, incluida la hora

á| raw(n): almacena datos binarios de longitud fija

á| long raw : almacena datos binarios de longitud variable

á| rowid: almacena identificadores de direcciones de fila

á| etc.
Además es importante señalar que el programador puede definir sus propios tipos de datos a
partir de los ya definidos.

º  


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

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

Pueden tener como máximo 30 caracteres empezando siempre por una letra, que puede ir
seguida por otras letras, numeros, $, # ó _. Es importante destacar que PL/SQL no

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


contener espacios ni signos de puntuación.

   

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

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

%& >  &  ! ÿ 6 ÿI1- : <6 J #  

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

que hacerlo una a una.

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



%!  68 ';+()"


  68'(,0)"

%&
/ '@)  6 1-K2 K"

999

 $%&
$'()%&

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

%ROWTYPE : crea una variable registro cuyos campos se corresponden con las columnas de
una tabla o vista.

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

otra de la siguiente forma:


 4A"
De esta forma la variable total tendrá las mismas características que la variable cantidad.
Otro ejemplo seria declarar una variable que fuera del mismo tipo que la columna nombre de

la tabla profesor.

%& $  %& 45A"

—** 

La variable será local para el bloque en el que ha sido declarada y global para los bloque
hijos de éste, mientras que las variables declaradas en los bloque hijos no son globales a los

bloques padre.

›  

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

siguiente forma:

%& >  &  2 ! 1- #  "

m 

Asignación :=
AND
Lógicos OR
NOT
Concatenación ||
Is null
=
!=
<>
<
>
Comparación
<=
>=
between...and
like
in
y sus correspondientes negaciones
Aritméticos + - * / **


Ë
    

En PL/SQL tenemos las mismas funciones predefinidas que en SQL (AVG, MIN, MAX, COUNT,
SUM, etc), pero tenemos que tener dos cosas muy claras a la hora de utilizarlas y son:

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

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


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

valor nulo.

à 

Podemos utilizar etiquetas para poder irnos a cualquier parte del programa utilizando la
sentencia GOTO siempre y cuando se cumplan las siguientes reglas:

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

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


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


En cualquier subprograma podemos distinguir:

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

valor de retorno.

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

excepciones.

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

artículos anteriores:


  

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

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

Ë
 

Las funciones son muy similares a los procedimiento con la diferencia que éstas siempre
devolverán un valor. Su estructura es la siguiente:
 ÿ  <6 %& <
 ÿ'! C%  ) 6 !

2 ÿ!  
# 



 

 

6 #   ! "

ÿ
!
 

"

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

 

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

Dentro de los parámetros podemos distinguir dos tipos:

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

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

Además podemos hacer el paso de parámetros de un tipo a otro. Generalmente si los tipos
son compatibles PL/SQL lo hace automáticamente. En cualquier caso, podemos hacerlo de

forma manual utilizando las siguientes notaciones:

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

en suposición.

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

indica al compilador correspondencia.

á| Mixta: nos permite usar las dos notaciones anteriores.

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

conversión de tipos.

Tenemos la especificación de un procedimiento como esta:

6  !  % '

$ !  %  +


  >=(

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



%$ !  %  "

 >='L0)



999

F F !
  !  % '%$ !  % +  )"

F F %  !  % '%$ !  %  - $ !  % +  - 


 )"

999

"

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

localidad al mismo tipo que aula.

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

Nos permite pasar valores a un subprograma. Dentro


del subprograma, el parámetro actuá como una
"#
constante. Puede ser una variable, constante, literal o
expresión.
Permite devolver valores al bloque que llamó al
subprograma. Dentro del subprograma, el parámetro
(%
actúa como una variable no inicializada. Solo puede ser
una variable.
Permite pasar un valor inicial y devolver un valor
"# actualizado. Dentro del subprograma, el parámetro
(% actuá como variable inicializada. Puede intervenir otras
expresiones. El valor actual debe ser una variable.

El formato genérico es el siguiente:

%& #  &  ÿ : 6 :  6 ! 

ÿ I 1- : <6J #  

Además es importante recordar que al especificar parámetros debemos indicar el tipo, pero
no el tamaño.


›
  

      

Cuando creamos subprogramas con SQL * PLUS utilizando los comandos CREATE, Oracle
automáticamente compila el código fuente, genera el código objeto y los guarda en el

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

Para volver a compilar un subprograma almacenado utilizaremos la orden ALTER en vez del
CREATE y su formato es el siguiente:

 I6 : <6J %& &!  % 8"

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

esta;


 + 262'+?+M0) 7 % 62$26 ./  % - ,%& &!  % ,"

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

 I6 : <6J %& &!  % "

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

puede llamarse a si mismo.




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

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

Oracle. Empezaremos con la utilización de cursores.

Hasta ahora hemos utilizado  +,cuando devolvíamos el resultado de una

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

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

Para que no nos salte un error en estos casos debemos utilizar los  +

› 


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

más de una fila.


Tenemos 4 operaciones básicas para trabajar con un cursor explícito.
1.| Declaración del cursor: lo tenemos que declarar en la zona de declaraciones, con el
siguiente formato: 62 %&
   2   
 2"

2.| Apertura del cursor: Deberá colocarse en la zona de instrucciones, con el siguiente
formato:
 %&
  "

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

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

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

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


<= %&
    I#  &  :   #  & J"

Si tenemos una única variable que recoge los datos de todas las columnas, el
formato de la variable seria el siguiente:
#  &  %&
  45A"

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

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

4.| - Cierre del cursor:


2 %&
  "

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



62 ? 2 2 %& + !  <8 & "

>% >=('?()"

> ! >=('(0)"



 ?"



<= ?  >%+ > ! "

 5= ?4<6"

82$6696$'>% :: ,, :: > ! )"

 "

2 ?"

"

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


que sí se utilizaba en los cursores implícitos.
Además podéis ver que después del FETCH hemos comprobado si nos devuelve valores con
la línea del EXIT. Es algo importante ya que si no nos devuelve nada el LOOP se

interrumpirá.

‘  


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

á| $-(#. devuelve verdadero si el último FETCH ha recuperado algún valor; en


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

á| $#(%-(#. hace justamente lo contrario al anterior.


á| $'()/(#% nos devuelve el número de filas recuperadas hasta el momento.

á| $" (
# devuelve verdadero si el cursor está abierto.

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



62 ? 2 2 %& 7 % 7&  5= -, ?,"

>% >=('?@)"



 ?"



<= ?  >%"

 5= ?4<6"

82$6696$ '?456 :: >%)"

 "

2 ?"

"

    
      
 

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

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

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


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

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

El ejemplo nos muestra los futbolistas de un equipo cualquiera.


   6 # $7&  $! $ N!'
 N >=()

2

> N >=('L)"

62 ? 2 2 %& 7 % 7&  ./


 N-> N"

>% >='?@)"



# N1-
 N"

 ?"

<= ?  #%"

5= ?4<6 

82$6696$'>%)"

<= ?  >%"

 "

2 ?"

"

    
  

Si os fijáis en el siguiente ejemplo veréis que en la cláusula where se incluye una variable
que se deberá declarar previamente. Este tipo de variables recibe el nombre de variables de

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

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

   !
! 
 # $O  '
 N #
/ ()

2

# N #
/ ('L)"


 
?  
 %& 7 % O  ./
-# N"

#% #
/ ('?@)"



# N1-
 N"


?"

<=
?  #%"

5=
?47 

82$6696$'#%)"

<=
?  #%"

 "

2
?"

"
›Ëm  !mm

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 presenta el cursor utilizando el siguiente formato: FOR nombreVarReg IN

nombreCursor

LOOP «. END LOOP;

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

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

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

realizaran las acciones que correspondas hasta llegar al END LOOP.

Este es un ejemplo del LOOP «. END LOOP:




 
(  
 %& + ! +   7 % O  ./  ?(00"



< #  
( 

82$6696$ '# 9%& :: ,F, ::# 9!  :: ,F, :: # 9   )"

 "

"

›
  

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

62 %&
  ÿ'! C%  ) 2 2   
 
  N  #  C

 ! C%  "

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

sintaxis:
%&   ÿ !  ÿI1-:<6J #  

Todos los parámetros formales de un cursor son parámetros de entrada y su ámbito es local
al cursor por eso sólo pueden ser referenciados dentro de la consulta.

Un ejemplo seria el siguiente:



999

62 ? '#!  %& + #   %& <6 ?P0)  


 7
/ + %& <8

%! 5=   -#    ! -#! "

 &  
 
 ! C%    / %    7 % 1

 %&
  ÿ'! C%  )"

‘
 › 


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

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

afectado a ninguna fila.

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


una o mas filas

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

update, delete o select into

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

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

SQL.

Es importante tener en cuenta una serie de cosas:

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

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

á NO_DATA_FOUND: si la consulta no devuelve ninguna fila


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

Cuando un select into hace referencia a una función de grupo nuca se levantará la excepción
NO_DATA_FOUND y SQL%FOUND siempre será verdadero. Esto se explica porque las
funciones de grupo siempre devuelven algún valor (NULL se considera un valor).

Ê 
  
 "   

Para realizar una actualización con un cursor tenemos que añadir la siguiente FOR UPDATE al
final de la declaración del cursor:

62 %& $
  

  < 6

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

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

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

mediante la orden FETCH.

I6:J999 5= 6 < %& $


  9

Os pongo un ejemplo para que quede claro:

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

porcentaje se indicará también en la llamada.

   6 & $  '%$ ! 68+ 


68)

2

62
2 2 7
+   <8 %!  5=
$ !-%$ !

< 6"


45A"


68 ';)"




"

<=
 "

5=
4<6 


1-' 9 D?00 )E 
"

6 %!  2  - Q


5= 6 <

<=
 "

 "

"
También podemos usar ROWID en lugar de FOR UPDATE. ROWID nos indicará la fila que se
va a actualizar. Para ello, al declarar el cursor en la cláusula SELECT indicaremos que

seleccione también el identificador de fila:

62 %& $
  2 2
 % ?+
 % (+9995 <8  & "

Al ejecutarse el FETCH se guardará el número de fila en una variable y después ese número
se podrá usar en la cláusula WHERE de la actualización:

I6 : J 999 5= 5 - #  & $ .

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

   6 & $  '%$ ! 68+ 


68)

2

62
2 2 7
+  +5 <8 %!  5=
$ !-%$ !

< 6"


45A"


68 ';)"




"

<=
 "

5=
4<6 


1-' 9 D?00 )E 
"

6 %!  2  - Q


5= 5 -

95"

<=
 "

 "

"

En este artículo del Manual de PL/SQL de Oracle vamos a ver lo que son las excepciones,
para qué sirven y cómo utilizarlas. Daremos un repaso también a los tipos de excepciones,

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

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

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

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


#  

  m


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


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

para definir qué se debe hacer frente a errores en sentencias definidas por el usuario.
Cuando se produce un error PL/SQL levanta una excepción y pasa el control a la sección

excepción correspondiente al bloque PL/SQL.

El formato sería el siguiente:



999999999

999999

999999



5= %& $
!
 =

 

 "

999999

ÿ5= =2 =  

 "

"

à

    

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

son las más comunes:

001: Se produce cuando select « into devuelve más de una fila.

00 : se produce cuando un select «. into no devuelve ninguna fila.

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


validos.

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


conectados.

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


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

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

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

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


*0 : se produce cuando se intenta convertir una cadena a un valor numérico.
Hay alguna más pero estas son las más utilizadas y tenemos que tener en cuenta que no es
necesario declararlas en la sección DECLARE.

à

       

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

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

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

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

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



999

%!  $% "

999



999

< !
  5 %B%  %C % =

2 %!  $% "

 <"

999



5= %!  $% = 82$6696$'K%!  



K)"

999

"

m 

 

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

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

SQLERRM. Cuando se produce un error de estos se trasfiere directamente el control a la


sección EXCEPTION donde se tratara el error en la clausula WHEN OTHERS de la siguiente

forma:

5= =2 = 82$6696$',  ,::23::2389)


Ê "
   ‘ºà‘º›‘ëºmà m 

En el paquete DBMS_STANDARD se incluye un procedimiento llamado


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

Su formato es el siguiente:

2$$'% $  +%  O $  )"

Es importante saber que el número de error está comprendido entre -20000 y -20999 y el
mensaje es una cadena de caracteres de hasta 512 bytes.

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

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

   6 & $/  ' %! 68+ / $& 68)

2

/ $
  68"



2
 /   / $
  7 % %!  ./ $ %! - %! "

7 / $
   6 / 

2$$'F(00?0+,   / ,)"

!  %!    / -/ $


  Q / $& ./ $ %! - %! "

 7"

 & $/ "

/(
  

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


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

y algunos ejemplos interesantes.

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

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

Un ejemplo:



9999
!  %    -(0 ./ $ %-?0*"

!   #   ! -,! R, ./ $ %-(00"

%% . S"

999



5= =2 =

 &
S . S"

"

›  "    


    

  

/

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

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

los datos modificados.

'3

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

haber producido en la misma, liberando las filas bloqueadas. Se utiliza especialmente cuando
no se puede concluir una transacción porque se han levantado excepciones.

*

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


junto con rollback permitiendo deshacer cambios hasta los savepoint.

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

 # ! % "

'3

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

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

estos cambios no serán deshechos.

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

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

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


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

  !
! 
 !  & '7  %& )

& 

 # !  "

   %! #   ',! % 7 ,)"

 # !  "

   %! #   ',  7 ,)"

 # ! "

7 7 -? / 

 &
S   "

 7 7 -( / 

 &
S  "

 &
S   "

 7"


%%"


!

./  / / 

 &
S

 !  & "

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

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

siguiente artículo.

En el presente artículo vamos a estudiar acerca de los triggers, donde veremos qué son y
cómo se construyen, comenzando con los trigger de tablas y más tarde veremos los trigger

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

ë   

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

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

cuando se producen ciertos eventos asociados a la tabla.

Se suelen utilizar para prevenir transacciones erróneas y nos sirven también para
implementar restricciones de integridad o seguridad.
Su formato básico es el siguiente:

  !
  %& $ 

I& 7 : 7 J I  :   : !  ÿ7  $


 % J

ÿ I& 7 : 7 J I  : :!  ÿ7  $


 % J

 %& $ &

ÿ7
/ I . :   %  : ./  '

)J

DE
% R   ED

ÿ




 

& 

 

 

ÿ
!


!
 

"

à    

 : elemento que dispara el trigger

: nombre del trigger que tiene que ser único.

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

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

41: salta por cada fila afectada.

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

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

Tenemos que tener en cuanta unos cuantos aspectos:

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

porque el valor :new es nulo

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

porque el :old es nulo.

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

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

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

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


   !
   $ 

7 !  7  

 %! 

7
/ .

& 

    #  

', / %7
  , :: 1 9%$ %! )"

"

m   

   

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

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

triggers del tipo before.... for each statement

2.| Para cada fila afectada por la orden:

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

b) se ejecuta la actualización de la fila

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


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

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

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

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

Ejemplo:

  !
  %& $ 

& 7     

& 

7   / 

99999

 7   / 

9999

 7 !  / 

999

 7

9999

"
   
 

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

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

La sintaxis de este tipo de trigger es la siguiente:

 ÿ !
   %& $ 

  7 I   :   : !  ÿ7


 % J

ÿ  I   :   : !  J

 %& #

ÿ 7
/ .

ÿ




 

& 

 

 

ÿ
!


!
 

"

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

darnos problemas y no dejar ejecutarse la orden correctamente.

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

tablas que forman la vista.

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

  !
  $& $ %!

  7    %! 

7
/ .

& 

  7 % %! ./ %!$%-1 9


"

    

Estos trigger se disparan cuando se arranca o para la base de datos, entra o sale un usuario,
cuando se crea, modifica o elimina un objeto, etc.
En Oracle para crear este tipo de trigger tenemos que tener privilegios de Administer
database trigger.

La sintaxis de este trigger seria la siguiente:

 ÿ !
   %& $ 

I & 7 : 7 J I   #    7


 :   #    % J

 I   &  : 
/ % J ÿ./  '

)


 !    '& N D23)

Donde la lista de eventos de definición puede tener uno o más eventos DDL separados por or
y la lista de eventos del sistema igualmente separados por or.

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

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

* 5 


STARTUP AFTER Después de arrancar la instancia
SHUTDOWN BEFORE Antes de apagar la istancia
Después de que el usuario se conecte a
LOGON AFTER
la base de datos.
LOGOFF BEFORE Antes de la desconexión de un usuario
SERVERERROR AFTER Cuando ocurre un error en el servidor
BEFORE | Antes o después de crear un objeto en
CREATE
AFTER el esquema
BEFORE | Antes o después de borrar un objeto en
DROP
AFTER el esquema
BEFORE | Antes o después de cambiar un objeto
ALTER
AFTER en el esquema
BEFORE | Antes o después de ejecutar un
TRUNCATE
AFTER comando truncate
BEFORE | Antes o después de ejecutar un
GRANT
AFTER comando grant
BEFORE | Antes o después de ejecutar un
REVOKE
AFTER comando revoke
BEFORE | Antes o después de ejecutar cualquier
DLL
AFTER comando de definición de datos

Oracle tiene algunas funciones que permiten acceder a los atributos del evento del disparo
ORA_YSEVENT, ORA_LOGIN, etc. Estas funciones pueden usarse en la clausula WHEN o en el
cuerpo del disparador. En el manual de Oracle podéis encontrar el listado de todas estas

funciones.

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

de datos:

  !
 
 

7 

   & 

& 

  
  $
  ' + %% + # )

#   I$$62+ 2A2828+ $2A2>)"

"

ù*6 6 


(,   

Y ?   



  
   
  
 

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

forma detenida.

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

Un paquete consta de los siguientes elementos:

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

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

variables, cursores, excepciones, etc.

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


accesibles solamente desde los objetos del paquete.

La sintaxis de la cabecera es la siguiente:


 ÿ !
 !
S  %& $! N  



  !T& 


 !
7

   &!  % 

 %& $! N  "
La sintaxis del cuerpo sería la siguiente:


 ÿ !
 !
S  &G %& $! N  



  ! #  


  &!  % 

ÿ& 

 

  
 

 %& $! N  "

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

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

DE  &
ED

  !
!
S  & $ %! 

A $ $ %!  

'%$ %!  %! 9 %!$4A+

!  %! 9 ! 4A+

  %! 9 4A+

 !  %  %! 9 !$4A)"

! 
 # $! $% '#$
 %! 9 %!$4A)"

! 
 # $! $ ! '#$ ! %! 9 ! 4A)"

7
   '#$
 %! 9 %!$4A)

  $ $ %! "

 &
$ %! "

DE  ! ED

  !
!
S  &G &
$ %! 

#$ %! $ $ %! "

! 
 # $ %! " DE ! 
%  ! # ED

! 
 # $! $%  '#$
 %! 9 %!$4A)



& 


 %!$+ ! +  +  !$  #$ %! 7 % %! ./

%!$-#$
"

# $ %! "

 # $! $% "

! 
 # $! $ !  '#$ ! %! 9 ! 4A)


& 


 %!$+ ! + + !$  #$ %! 7 % %! ./

! -#$ ! "

# $ %! "

 # $! $ ! "

7
   '#$
 %! 9 %!$4A)

  $ $ %!



& 


 %!$+ ! + + !$  #$ %! 7 % %! ./

%!$-#$
"

! 
 # $ %!



& 

82$6696$'#$ %! 9%$ %!  :: ,E, :: #$ %! 9 !  :: ,E,

:: #$ %! 9  :: ,E,:: #$ %! 9 !  % )"

 # $ %! "

 &
$ %! "

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

visualizar sus datos.

Ê "
          

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

distintas:

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

dentro del paquete por otro objeto declarado en el mismo.


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

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


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

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

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

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


nombre_paquete.nombre_procedimiento(lista de parametros);



  
  
En los paquetes también podemos introducir cursores, para ello debemos declararlo en la
cabecera del paquete indicando su nombre, los parámetros y tipo devuelto. Para que lo veáis

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

   U %!  2

99999

62 6 %! 45A"

999

 %! "

   U A %!  2

9999

62 6 %! 45A

2 E <8 %!  5=    ?0000"

9999

 %! "

Los paquetes suministrados por Oracle son:

2   1   7
 $
/ G &

&%$  1   7
  $ ! 
$ 

&%$!1
 7
 !$ 

&%$N 1 N  R N  7 % C%


9

#(%7: sql dinámico significa que el programa es capaz de ejecutar órdenes de definición y manipulación

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

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



999999

$
  1- 82$239$62"

82$2392'$
  +  

+82$239>L)"

#$% 1-82$2396'$
  )"

82$2392$62'$
  )"

999999

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

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

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


No os preocupéis si no habéis terminado de entenderlo ya que dedicaremos un articulo
completo a la utilización de DBSM_SQL.

Вам также может понравиться