142 - Disparador de inserción (insert trigger) |
Una librería almacena los datos de sus libros en una tabla denominada "libros" y en otra tabla llamada "ventas", las ventas de los mismos.
Eliminamos las tablas si existen:
if object_id('ventas') is not null drop table ventas; if object_id('libros') is not null drop table libros;
Creamos las tablas, con las siguientes estructuras:
create table libros( codigo int identity, titulo varchar(40), autor varchar(30), precio decimal(6,2), stock int, constraint PK_libros primary key(codigo) ); create table ventas( numero int identity, fecha datetime, codigolibro int not null, precio decimal (6,2), cantidad int, constraint PK_ventas primary key(numero), constraint FK_ventas_codigolibro foreign key (codigolibro) references libros(codigo) );
Ingresamos algunos registros en "libros":
insert into libros values('Uno','Richard Bach',15,100); insert into libros values('Ilusiones','Richard Bach',18,50); insert into libros values('El aleph','Borges',25,200); insert into libros values('Aprenda PHP','Mario Molina',45,200);
Cuando ingresamos un registro en "ventas", debemos:
- controlar que el código del libro exista en "libros" (lo hacemos con la restricción "foreign key" establecida en "ventas"),
- controlar que exista stock, lo cual no puede controlarse con una restricción "foreign key" porque el campo "stock" no es clave primaria en la tabla "libros"; tampoco puede establecerse una restricción "check", porque ese tipo de restricciones no pueden hacer referencia a campos de otras tablas.
- disminuir el stock en la tabla "libros".
Creamos un disparador para que se ejecute cada vez que una instrucción "insert" ingrese datos en "ventas"; el mismo controlará que haya stock en "libros" y actualizará el campo "stock":
create trigger DIS_ventas_insertar on ventas for insert as declare @stock int select @stock= stock from libros join inserted on inserted.codigolibro=libros.codigo where libros.codigo=inserted.codigolibro if (@stock>=(select cantidad from inserted)) update libros set stock=stock-inserted.cantidad from libros join inserted on inserted.codigolibro=libros.codigo where codigo=inserted.codigolibro else begin raiserror ('Hay menos libros en stock de los solicitados para la venta', 16, 1) rollback transaction end
Ingresamos un registro en "ventas":
insert into ventas values('2018/04/01',1,15,1);
Al ejecutar la sentencia de inserción anterior, se disparó el trigger, el registro se agregó a la tabla del disparador ("ventas") y disminuyó el valor del campo "stock" de "libros". Verifiquemos que el disparador se ejecutó consultando la tabla "ventas" y "libros":
select *from ventas; select *from libros where codigo=1;
Ingresamos un registro en "ventas", solicitando una cantidad superior al stock:
insert into ventas values('2018/04/01',2,18,100);
El disparador se ejecuta y muestra un mensaje, la inserción no se realizó porque la cantidad solicitada supera el stock.
Finalmente probaremos ingresar una venta con un código de libro inexistente:
insert into ventas values('2018/04/01',5,18,1);
El trigger no llegó a ejecutarse, porque la comprobación de restricciones (que se ejecuta antes que el disparador) detectó que la infracción a la "foreign key".