Pulse aquí para obtener el archivo

Anuncio
Restricciones y Triggers
Las restricciones son declaraciones de condiciones sobre la base de datos que debe permanecer
verdaderas. Éstas incluyen restricciones basado en atributos, en tuplas, en llaves, y restricciones de
integridad de referencial. El sistema inspecciona la violación de las restricciones sobre acciones que
pueden causar una violación, y aborta la acción de acuerdo con lo especificado en la restricción. La
información sobre las restricciones del SQL puede encontrarse en el libro de texto. La implementación de
restricciones en Oracle difiere del standard SQL, ver documento [1]
Los disparadores (o triggers) son una estructura especial del PL/SQL similar a los procedimientos. Sin
embargo, un procedimiento se ejecuta explícitamente desde otro bloque vía un procedimiento de llamado,
mientras un disparador se ejecuta implícitamente siempre que el evento activando ocurra. El evento que
activa el disparador es una orden de INSERCIÓN (INSERT), de BORRADO (DELETE), o de
ACTUALIZACION (UPDATE). La elección del momento adecuado o puede ser ANTES o DESPUÉS
DE (BEFORE o AFTER). El trigger puede estar definido a nivel de fila o de instrucción, donde los
primeros realizan la acción una vez para cada fila afectada en el evento y los segundos realizan la acción
una vez por toda la instrucción.
●
Restricciones:
● Difiriendo la comprobación de una restricción
● Violación de una Restricción
●
Triggers:
● Sintaxis Básica de un Trigger
● Ejemplo de Trigger
● Desplegando la Definición de Errores en el Trigger
● Viendo los Triggers Definidos
● Borrando Triggers
● Desactivando Triggers
● Abortando Triggers con Error
● Mutating Table Errors
Difiriendo La Comprobación de una Restricción
A veces es necesario diferir la comprobación de ciertas restricciones, como en el problema " del pollo-y-el-huevo".
Suponga que nosotros queremos decir:
CREATE TABLE Pollo (polloID INT PRIMARY KEY,
huevoID INT REFERENCES Huevo(huevoID));
CREATE TABLE Huevo (huevoID INT PRIMARY KEY,
polloID INT REFERENCES Pollo(polloID));
Pero si tecleamos las declaraciones anteriores en Oracle, nosotros conseguiremos un error. ¡La razón es que la
instrucción CREATE TABLE para Pollo se refiere a la tabla Huevo , que no se ha creado todavía! Creando el
Huevo no ayudarán mucho, porque el Huevo se refiere para un Pollo .
Para trabajar alrededor de este problema, nosotros necesitamos comandos que permitan la modificación del
esquema SQL. Primero, creamos el Pollo sin las declaraciones de llave foránea:
CREATE TABLE Pollo (polloID INT PRIMARY KEY,
huevoID INT);
CREATE TABLE Huevo (huevoID INT PRIMARY KEY,
polloID INT);
Luego adicionamos las restricciones de llave foránea:
ALTER TABLE Pollo ADD CONSTRAINT polloREFHuevo
FOREIGN KEY (huevoID) REFERENCES Huevo (huevoID)
INITIALLY DEFERRED DEFERRABLE;
ALTER TABLE Huevo ADD CONSTRAINT huevoREFPollo
FOREIGN KEY (polloID) REFERENCES Pollo (polloID)
INITIALLY DEFERRED DEFERRABLE;
INITIALLY DEFERRED DEFERRABLE le dice a Oracle que haga la comprobación de restricción diferida. Por
ejemplo, para insertar (1, 2) en el pollo y (2, 1) en el huevo, nosotros usamos:
INSERT INTO Pollo VALUES(1, 2);
INSERT INTO Huevo VALUES(2, 1);
COMMIT;
Dado que hemos declarado las restricciones de llave foránea como "diferidas", ellos sólo se verifican en el punto de
Commit. (Sin diferir la verificación de la restricción, nosotros no podemos insertar nada en las tablas Pollo y
Huevo, porque el primer INSERT siempre viola la restricción).
Finalmente, para borrar las tablas, primero tenemos que borrar las restricciones, porque Oracle no permite borrar
una tabla que esta siendo referenciada por otra tabla.
ALTER TABLE Huevo DROP CONSTRAINT huevoREFPollo;
ALTER TABLE Pollo DROP CONSTRAINT polloREFHuevo;
DROP TABLE Huevo;
DROP TABLE Pollo;
Violación de una Restricción
En general, Oracle devuelve un mensaje del error cuando una restricción se viola. Específicamente para los
usuarios de JDBC, esto significa que se devuelve una SQLException. Los programadores deben usar la
instrucción WHENEVER y/o verificar el contenido del SQLCA (para los usuarios de Pro*C) o capturar la
excepción SQLException (para usuarios de JDBC) para conseguir el código de error devuelto por Oracle.
Algunos números del código de error específicos son: 1 para las violaciones de restricciones de llave primaria,
2291 para las violaciones de llaves foráneas, 2290 para las violaciones de restricciones CHECK de atributo y de
tupla. Oracle también proporciona mensaje de error simples, que tienen un formato similar a lo siguiente:
ORA-02290: check constraint (YFUNG.GR_GR) violated
o
ORA-02291: integrity constraint (HONDROUL.SYS_C0067174) violated - parent
key not found
Para más detalles sobre cómo es el manejo de errores, por favor eche una mirada al “tratamiento de
errores de Pro*C” o a la sección de las Recuperando Excepciones de “tratamiento de errores de JDBC”.
Sintaxis Básica de un Trigger
A continuación se presenta la sintaxis para crear un disparador en Oracle (difiere ligeramente de la sintaxis del SQL
Standard):
CREATE [OR REPLACE] TRIGGER < nombre_trigger >
{BEFORE|AFTER} {INSERT|DELETE|UPDATE} ON <NombreTabla>
[REFERENCING [NEW AS <nuevo_Nombre_Fila >] [OLD AS <Viejo_Nombre_Fila>]]
[FOR EACH ROW [WHEN (<condicion_Del_Trigger >)]]
<Cuerpo_Del_Trigger>
Algunos puntos importantes para notar:
● Se pueden crear triggers para tablas, BEFORE y AFTER. ( Triggers INSTEAD OF solo están disponibles
para vistas; típicamente ellos se usan para llevar a cabo actualizaciones de vistas.)
● Se pueden especificar hasta tres eventos de disparo usando el conector OR. Además, UPDATE puede ser
opcionalmente seguido de la palabra clave OF y una lista de atributos en <NombreTabla>. Si esta
presente la cláusula OF define que el evento solo será una actualización del atributo(s) listados después del
OF. Aquí son algunos ejemplos:
... INSERT ON R ...
... INSERT OR DELETE OR UPDATE ON R ...
... UPDATE OF A, B OR INSERT ON R ...
●
Si se especifica la opción FOR EACH ROW, el trigger es a nivel de fila; De otra forma el trigger será a
nivel de instrucción..
● Sólo para triggers a nivel de fila:
● Las variables especiales NEW y OLD están disponibles para referirse respectivamente a las tuples nueva
y vieja. Nota: En el cuerpo del disparador, NEW y OLD deben ser precedidos por dos puntos (":"),
pero en la cláusula WHEN, ellos no tienen los dos puntos precedentes! Vea el ejemplo debajo.
● La cláusula REFERENCING puede ser usada para asignar alias a las variables NEW y OLD.
● Una restricción trigger puede ser especificada en la cláusula WHEN, encerrada entre paréntesis. La
restricción del disparador es una condición SQL que debe satisfacerse para que Oracle dispare el
trigger. Esta condición no puede contener subconsultas. Sin la cláusula WHEN, el trigger se dispara
para cada fila.
● El <Cuerpo_Del_Trigger> es un bloque PL/SQL, en lugar de una secuencia de instrucciones SQL. Oracle
ha puesto ciertas restricciones sobre lo que usted puede hacer en el <Cuerpo_Del_Trigger>, para evitar
situaciones dónde un disparador realiza una acción que activa un segundo trigger que entonces activa un
tercero que podría crear, potencialmente, una vuelta infinita y así sucesivamente. Las restricciones sobre el
<Cuerpo_Del_Trigger> incluyen:
●
●
●
Usted no puede modificar la misma relación cuya modificación es el evento que activa el disparador.
Usted no puede modificar una relación conectada a la relación del disparador por otra restricción como
una llave foránea.
Ejemplo de Trigger
Nosotros ilustramos la sintaxis de Oracle por crear un disparador a través de un ejemplo basado en las siguiente dos
tablas:
CREATE TABLE TA (a INTEGER, b CHAR(10));
CREATE TABLE TB (c CHAR(10), d INTEGER);
Nosotros creamos un disparador que puede insertar un tupla en TB cuando un tupla se inserta en TA.
Específicamente, el disparador verifica si la nueva tupla tiene un primer componente 10 o menos, y en ese caso
inserta la tupla inversa en TB:
CREATE TRIGGER dispara1
AFTER INSERT ON TA
REFERENCING NEW AS nuevaFila
FOR EACH ROW
WHEN (nuevaFila.a <= 10)
BEGIN
INSERT INTO TB VALUES(:nuevaFila.b, : nuevaFila.a);
END dispara1;
.
run;
Note que la instrucción CREATE TRIGGER la finalizamos con punto y run, como en todas las declaraciones de
PL/SQL. La ejecución de la instrucción CREATE TRIGGER solo crea el trigger, no lo ejecuta. Sólo un evento
de activación, como una inserción en TA (para este ejemplo), causa que el trigger se ejecute.
Desplegando la Definición de Errores en el Trigger
Como en los procedimientos de PL/SQL, si usted obtiene un mensaje
Warning: Trigger created with compilation errors.
usted puede ver los mensajes del error tecleando
show errors trigger <trigger_name>;
Alternativamente, usted puede digitar, SHO ERR (abreviando por SHOW ERRORS) para ver el más reciente error
de la compilación. Observe que el número de la línea donde se reporta que ocurren los errores ocurren no es exacta.
Viendo los Triggers Definidos
Para ver una lista de todos los disparadores definidos, se usa la consulta:
select trigger_name from user_triggers;
Para más detalles sobre un trigger en particular:
select trigger_type, triggering_event, table_name,
referencing_names, trigger_body
from user_triggers
where trigger_name = '<Nombre_Trigger>';
Borrando Triggers
Para borrar un trigger ejecuto la instrucción:
drop trigger <Nombre_Trigger>;
Desactivando Triggers
Para desactivar o activar un trigger:
alter trigger <Nombre_Trigger> {disable|enable};
Abortando Triggers con Error
Los disparadores pueden usarse a menudo para reforzar a una restricción.
La cláusula WHEN o el cuerpo del disparador pueden verificar la violación de ciertas condiciones y pueden
señalar un error que usando la función incorporada RAISE_APPLICATION_ERROR del Oracle. La acción que
activó el trigger (la inserción, actualización, o borrado) se abortaría.
Por ejemplo, el siguiente trigger refuerza la restricción de que la edad de la persona sea mayor o igual que cero
( Persona.edad >= 0):
create table Persona (edad int);
CREATE TRIGGER ChequeaEdadPersona
AFTER INSERT OR UPDATE OF edad ON Persona
FOR EACH ROW
BEGIN
IF (:new.edad < 0) THEN
RAISE_APPLICATION_ERROR(-20000, 'No se permite una edad negativa');
END IF;
END;
.
RUN;
Si intentamos ejecutar la inserción:
insert into Person values (-3);
Obtendremos el siguiente mensaje de error:
ERROR at line 1:
ORA-20000: No se permite una edad negativa
ORA-06512: at "MYNAME.CHEQUEAEDADPERSONA", line 3
ORA-04088: error during execution of trigger 'MYNAME.CHEQUEAEDADPERSONA'
y nada se insertará. En general, los efectos del trigger y la declaración de activación son reversadas..
Errores de Tabla Mutante
A veces usted puede encontrar que Oracle informa un" error de tabla mutante" ("mutating table error") cuando su
trigger se ejecuta. Esto sucede cuando el disparador está preguntando o está modificando una" tabla mutante" la
cual es la tabla cuya modificación activó el disparador o una tabla que podría necesitar actualizarse debido a una
restricción de llave foránea con una política en cascada (CASCADE).
Para evitar errores de tabla mutante:
● Un trigger a nivel de fila no debe preguntar o modificar una tabla mutante. (por su puesto que NEW y
OLD todavía puede accederse por el disparador.)
● Un trigger a nivel de instrucción no debe preguntar o modificar una tabla mutante si el trigger se dispara
como resultado de un borrado en cascada.
Referencias
[1] http://www-db.stanford.edu/~ullman/fcdb/oracle/or-nonstandard.html#constraints
Descargar