Listado completo de tutoriales

144 - Disparador de actualización (update trigger)


Ver video

Podemos crear un disparador para que se ejecute siempre que una instrucción "update" actualice los datos de una tabla.

Sintaxis básica:

 create trigger NOMBREDISPARADOR
  on NOMBRETABLA
  for update
 as 
   SENTENCIAS

Analizamos la sintaxis:

"create trigger" junto al nombre del disparador; "on" seguido del nombre de la tabla para la cual se establece el trigger.

Luego de "for" se coloca el evento (en este caso "update"), lo que indica que las actualizaciones sobre la tabla activarán el trigger.

Luego de "as" se especifican las condiciones y acciones, es decir, las condiciones que determinan cuando un intento de modificación provoca las acciones que el trigger realizará.

El siguiente disparador de actualización se crea para evitar que se modifiquen los datos de la tabla "libros":

 create trigger DIS_libros_actualizar
  on libros
  for update
  as
    raiserror('Los datos de la tabla "libros" no pueden modificarse', 10, 1)
    rollback transaction

Entonces, creamos el disparador ("create trigger") dándole un nombre ("DIS_libros_actualizar") sobre una tabla específica ("libros") para ("for") el suceso de actualización ("update"). Luego de "as" colocamos las sentencias, las acciones que el trigger realizará cuando se intente actualizar uno o varios registros en "libros" (en este caso, impedir las modificaciones).

Cuando se ejecuta una instrucción "update" en una tabla que tiene definido un disparador, los registros originales (antes de ser actualizados) se mueven a la tabla virtual "deleted" y los registros actualizados (con los nuevos valores) se copian a la tabla virtual "inserted". Dentro del trigger se puede acceder a estas tablas.

En el cuerpo de un trigger se puede emplear la función "update(campo)" que recibe un campo y retorna verdadero si el evento involucra actualizaciones (o inserciones) en ese campo; en caso contrario retorna "false".

Creamos un disparador que evite que se actualice el campo "precio" de la tabla "libros":

 create trigger DIS_libros_actualizar_precio
  on libros
  for update
  as
   if update(precio)
   begin
    raiserror('El precio de un libro no puede modificarse.', 10, 1)
    rollback transaction
   end;

Empleamos "if update()" para que el trigger controle la actualización del campo "precio"; así, cuando el disparador detecte una actualización en tal campo, realizará las acciones apropiadas (mostrar un mensaje y deshacer la actualización); en caso que se actualice otro campo, el disparador se activa, pero permite la transacción.

Creamos un disparador de actualización que muestra el valor anterior y nuevo valor de los registros actualizados:

 create trigger DIS_libros_actualizar2
  on libros
  for update
  as
   if (update(titulo) or update(autor) or update(editorial)) and
    not (update(precio) or update(stock))
   begin
    select d.codigo,
    (d.titulo+'-'+ d.autor+'-'+d.editorial) as 'registro anterior',
    (i.titulo+'-'+ i.autor+'-'+i.editorial) as 'registro actualizado'
     from deleted as d
     join inserted as i
     on d.codigo=i.codigo
   end
   else
   begin
    raiserror('El precio y stock no pueden modificarse. La actualización no se realizó.', 10, 1)
    rollback transaction
   end;

Empleamos "if update" para que el trigger controle si la actualización se realiza en ciertos campos permitidos (titulo, autor y editorial) y no en los campos prohibidos (precio y stock)); si se modifican los campos permitidos y ninguno de los no permitidos, mostrará los antiguos y nuevos valores consultando las tablas "deleted" e "inserted", en caso que se actualice un campo no permitido, el disparador muestra un mensaje y deshace la transacción.

Note que el disparador no controla los intentos de actualización sobre el campo "codigo", esto es porque tal campo, no puede modificarse porque está definido "identity", si intentamos modificarlo, SQL Server muestra un mensaje de error y el trigger no llega a dispararse.

Servidor de SQL Server instalado en forma local.

Ingresemos el siguiente lote de comandos en el SQL Server Management Studio:

if object_id('libros') is not null
  drop table libros;

create table libros(
  codigo int identity,
  titulo varchar(40),
  autor varchar(30),
  editorial varchar(20),
  precio decimal(6,2), 
  stock int,
  constraint PK_libros primary key(codigo)
);

go

insert into libros values('Uno','Richard Bach','Planeta',15,100);
insert into libros values('Alicia en el pais...','Lewis Carroll','Planeta',18,50);
insert into libros values('El aleph','Borges','Emece',25,200);
insert into libros values('Aprenda PHP','Mario Molina','Nuevo siglo',45,200);

go

-- Creamos un disparador para evitar que se modifiquen los datos de la tabla "libros":
create trigger DIS_libros_actualizar
  on libros
  for update
  as
    raiserror('Los datos de la tabla "libros" no pueden modificarse', 10, 1)
    rollback transaction;

go

-- Intentamos realizar alguna actualización en "libros":
update libros set titulo='Alicia en el pais de las maravillas' where codigo=2;
-- El disparador se activó, mostró un mensaje y deshizo la actualización.

-- Eliminamos el disparador creado anteriormente:
drop trigger DIS_libros_actualizar;

go

-- Creamos un disparador que evite que se actualice el campo "precio" de la tabla "libros":
create trigger DIS_libros_actualizar_precio
  on libros
  for update
  as
   if update(precio)
   begin
    raiserror('El precio de un libro no puede modificarse.', 10, 1)
    rollback transaction
   end;

go

-- Veamos qué sucede si intentamos actualizar el precio de un libro:
update libros set precio=30 where codigo=2;
-- El disparador se activa, muestra un mensaje y deshace la transacción.

-- Veamos qué sucede al actualizar el campo "titulo":
update libros set titulo='Alicia en el pais de las maravillas' where codigo=2;
-- El disparador se activa y realiza la transacción

-- Lo verificamos consultando la tabla:
select * from libros;

-- Veamos qué sucede si intentamos actualizar el precio y la editorial de un libro:
update libros set precio=30,editorial='Emece' where codigo=1;
-- El disparador se activa, muestra un mensaje y deshace la transacción; 
--el registro no fue actualizado.

-- Lo verificamos consultando la tabla:
select * from libros;

-- Eliminamos el disparador creado anteriormente:
drop trigger DIS_libros_actualizar_precio;

go

-- Creamos un disparador de actualización que muestra el valor anterior y nuevo valor de los
-- registros actualizados. El trigger debe controlar que la actualización se realice en los 
-- campos "titulo", "autor" y "editorial" y no en los demás campos (precio y stock));
-- si se modifican los campos permitidos y ninguno de los no permitidos, mostrará los antiguos
-- y nuevos valores consultando las tablas "deleted" e "inserted", en caso que se actualice
-- un campo no permitido, el disparador muestra un mensaje y deshace la transacción:
create trigger DIS_libros_actualizar2
  on libros
  for update
  as
   if (update(titulo) or update(autor) or update(editorial)) and
    not (update(precio) or update(stock))
   begin
    select (d.titulo+'-'+ d.autor+'-'+d.editorial) as 'registro anterior',
    (i.titulo+'-'+ i.autor+'-'+i.editorial) as 'registro actualizado'
     from deleted as d
     join inserted as i
     on d.codigo=i.codigo
   end
   else
   begin
    raiserror('El precio y stock no pueden modificarse. La actualización no se realizó.', 10, 1)
    rollback transaction
   end;

go

-- Veamos qué sucede si modificamos campos permitidos:
update libros set editorial='Paidos', autor='Desconocido' where codigo>3;
-- El trigger se dispara y muestra los registros modificados, los valores antes 
-- y después de la transacción.

-- Veamos qué sucede si en la sentencia "update" intentamos modificar algún campo no permitido:
update libros set editorial='Paidos', precio=30 where codigo>3;
-- El trigger se dispara y muestra el mensaje de error, la transacción no se realizó.

-- Intentamos modificar el código de un libro:
 update libros set codigo=9 where codigo>=3; 
-- El disparador no llega a dispararse porque SQL Server muestra un mensaje de error ya que el
-- campo "codigo", por ser "identity", no puede modificarse.

Retornar