1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
/* Pregunta 2 Realiza un trigger de base de datos pregunta2 que se ejecute automáticamente en el momento de borrar pedidos no enviados. Dicho trigger se encargará de: - Reponer las existencias de cada artículo en la tabla artículos en la cantidad que figura en los detalles del pedido que van a ser borrados. - Borrar los detalles de ese pedido no enviado. */ -- show triggers; -- drop trigger t_2x02; delimiter $$ create trigger t_2x02 before delete on pedidos for each row begin update articulos a, detalle_pedidos d set a.existencias = a.existencias + d.unidades where a.cod_articulo = d.cod_articulo and d.cod_pedido = old.num_pedido; delete from detalle_pedidos where cod_pedido = old.num_pedido; end $$ delimiter ; -- delete from pedidos where enviado = 'N' and num_pedido = 42; |
Categoría: Programación
2×01: Transacción con método optimista
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
/* Examen de prueba: Pregunta 1 Realiza un procedimiento pregunta1 que a partir de un código de artículo y una cantidad disminuya las existencias de la tabla artículos de ese artículo en esa cantidad. Utiliza un tercer argumento de tipo out para indicar el resultado del procedimiento Ten en cuenta: - Si el artículo no existe entonces el tercer argumento devolverá -1. - Si el artículo existe pero no hay suficientes unidades del mismo, el tercer argumento devolverá -2 En los 2 casos anteriores no se llevará a cabo ninguna modificación de las existencias. Si el artículo existe y dispone de existencias suficientes, realizar la operación y validar los cambios. Utiliza transacciones. Durante el tiempo que dure el proceso de modificación, se reservará (bloqueará) la fila implicada hasta que se validen los cambios. El tercer argumento devolverá 1. Para cualquier situación de error que se pueda producir se actuará deshaciendo la operación y devolviendo un 0 en el tercer argumento del procedimiento. */ delimiter $$ drop procedure if exists 2x01 $$ create procedure 2x01( p_articulo char(4), p_cantidad int(11), out p_resultado int(1) ) begin declare v_cod_articulo char(4); declare v_existencias int(11); declare continue handler for sqlexception begin rollback; set p_resultado = 0; end; -- El articulo existe y hay suficientes existencias: if ( select true from articulos where cod_articulo = p_articulo and existencias >= p_cantidad ) then select cod_articulo, existencias into v_cod_articulo, v_existencias from articulos where cod_articulo = p_articulo for update; START TRANSACTION; update articulos set existencias = existencias - p_cantidad where cod_articulo = v_cod_articulo and existencias = v_existencias; set p_resultado = 1; commit; -- El articulo existe pero no hay existencias suficientes: elseif ( select true from articulos where cod_articulo = p_articulo ) then set p_resultado = -2; -- El articulo no existe: else set p_resultado = -1; end if; end $$ delimiter ; -- call 2x01( 'A001', 3, @resultado ); -- select @resultado as 'Resultado'; |
1×29: Transacción optimista
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
/* Ejercicio 29: Realizar un procedimiento que teniendo en cuenta el procedimiento transac6 del apartado 6.10.5 de los materiales implemente otro procedimiento similar pero utilizando la estrategia optimista, que asume que es muy poco probable que el valor de una fila que se acaba de leer con intención de modificarla un tiempo más tarde cambie antes de poder hacerlo; en ese caso como mínimo habrá que asegurarse de que la fila no ha sido modificada después de haber sido leída y si así ha sido entonces la transacción no debe llevarse a cabo aun pudiéndose realizar (ROLLBACK). */ delimiter $$ drop procedure if exists 1x29 $$ create procedure 1x29( p_id int, p_alumno varchar(30) ) begin declare textoError tinytext; declare todoOk boolean default true; declare v_alumno varchar(30); declare v_antes_id int; declare v_antes_alumno varchar(30); declare continue handler for sqlexception begin set textoError = "Sql Exception"; set todoOk = false; end; -- Se hace una copia del contenido antes de la transaccion: select id, alumno into v_antes_id, v_antes_alumno from alumnos where id = p_id; START TRANSACTION; -- select sleep(20); -- Se hace la actualizacion si los datos son los mismos que los obtenidos anteriormente: if (select true from alumnos where id = v_antes_id and alumno = v_antes_alumno) then update alumnos set id = p_id, alumno = p_alumno where id = v_antes_id and alumno = v_antes_alumno; else set textoError = "Los datos no eran los mismos, no se ha realizo la modificacion."; set todoOk = false; end if; if todoOk then commit; else select textoError; rollback; end if; end $$ delimiter ; -- call 1x29( 2, 'Pedro'); |
1×28: Cursor de actualización
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
/* Ejercicio 28: “Representación gráfica de los salarios de los empleados”. Realizar un procedimiento que utilice un cursor de actualización para rellenar la columna estrellas de la tabla empleados con un asterisco por cada 100 unidades de salario. Antes de realizar el ejercicio añade la columna estrellas a la tabla empleados (ALTER TABLE empleados ADD COLUMN estrellas VARCHAR(10)). Incluir los dos manejadores de error del ejercicio anterior. Ejemplo de funcionamiento: +-------+---------+-----------+ | NUMEM | SALARIO | ESTRELLAS | +-------+---------+-----------+ | 110 | 400 | **** | | 120 | 350 | *** | | 130 | 290 | ** | | 150 | 440 | **** | | 160 | 310 | *** | | 180 | 480 | **** | | 190 | 420 | **** | | 210 | 440 | **** | | 240 | 280 | ** | | 250 | 450 | **** | | 260 | 900 | ********* | | 270 | 380 | *** | ... ... */ -- alter table empleados add stars varchar(5); -- Añade una columna -- alter table empleados change stars estrellas varchar(5); -- Modifica el nombre de una columna -- alter table empleados modify estrellas varchar(10); -- Cambia el tipo de una columna. delimiter $$ drop procedure if exists 1x28 $$ create procedure 1x28() begin declare finCursor boolean default false; declare todoOk boolean default true; declare textoError tinytext; declare v_numem integer; declare c_empleados cursor for select numem from empleados for update; declare continue handler for not found set finCursor = true; declare continue handler for sqlexception begin set todoOk = false; set textoError = "Sql Exception"; end; START TRANSACTION; open c_empleados; fetch c_empleados into v_numem; while finCursor = false do update empleados set estrellas = lpad('', salario div 100, '*') where numem = v_numem; -- Lpad nos ahorra tener que hacer una iteracion solo para concatenar estrellas. fetch c_empleados into v_numem; end while; close c_empleados; if todoOk then commit; else select textoError; rollback; end if; end $$ delimiter ; -- call 1x28; -- select numem, salario, estrellas from empleados; |
1×27: Transacción for update
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
/* Ejercicio 27: Realizar un procedimiento que actualice el salario de los empleados, con una cantidad por hijo que se pase al procedimiento, para aquellos trabajadores que su comisión es nula. Durante el proceso de actualización debe garantizarse que ningún otro usuario pueda cambiar los datos que están siendo modificados. Utilizar un manejador de tipo SQLEXCEPTION (que incluya la operación ROLLBACK) para tratar cualquier situación de error distinta de la excepción NOT FOUND que también deberá manejarse. Al final del proceso, confirmar la transacción si la ejecución ha sido correcta. Ejemplo de funcionamiento. Antes de llamar al procedimiento de actualización: +-------+---------+----------+-------+ | numem | salario | comision | numhi | +-------+---------+----------+-------+ | 110 | 310 | NULL | 3 | | 120 | 350 | 110 | 1 | | 130 | 290 | 110 | 2 | | 150 | 440 | NULL | 0 | | 160 | 310 | 110 | 2 | | 180 | 480 | 50 | 2 | | 190 | 300 | NULL | 4 | … …. Después de ejecutar CALL EJERCICIO3_1(30); +-------+---------+----------+-------+ | numem | salario | comision | numhi | +-------+---------+----------+-------+ | 110 | 400 | NULL | 3 | | 120 | 350 | 110 | 1 | | 130 | 290 | 110 | 2 | | 150 | 440 | NULL | 0 | | 160 | 310 | 110 | 2 | | 180 | 480 | 50 | 2 | | 190 | 420 | NULL | 4 | ... ... */ delimiter $$ drop procedure if exists 1x27 $$ create procedure 1x27(prima int) begin declare v_numem integer; declare finCursor boolean default false; declare c_cursor cursor for select numem from empleados where comision is null and numhi > 0 for update; declare continue handler for not found set finCursor = true; declare exit handler for sqlexception begin rollback; select "Ocurrio un error"; end; START TRANSACTION; open c_cursor; fetch c_cursor into v_numem; while finCursor = false do update empleados set salario = salario + (prima * numhi) where numem = v_numem; fetch c_cursor into v_numem; end while; close c_cursor; commit; end $$ delimiter ; -- select numem, salario, comision, numhi from empleados; -- call 1x27(30); -- select numem, salario, comision, numhi from empleados; |
1×26: Triggers para auditar
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
/* Ejercicio 26: Realizar tres triggers "ejercicio26a", "ejercicio26b", y "ejercicio26c" que realicen una auditoria similar a la que realiza el trigger2 del apartado 9.3 de los materiales, pero para la tabla centros: El trigger ejercicio26a auditará las operaciones de inserción. El trigger ejercicio26b auditará las operaciones de modificación. El trigger ejercicio26c auditará las operaciones de borrado. Antes de realizar el ejercicio necesitarás tener creada la tabla: create table audita ( mensaje varchar(200) ) engine = innodb; */ -- Trigger A: Audita las operaciones de inserción. delimiter $$ create trigger t_aud_insercion after insert on centros for each row begin insert into audita values ( concat ( 'Inserccion realizada por ', user(), ' el dia ', now(), '. Valores insertados: "', new.numce, '", "', new.nomce, '" y "', new.seas, '"' ) ); end $$ delimiter ; -- Trigger B: Audita las operaciones de modificación. delimiter $$ create trigger t_aud_modificacion after update on centros for each row begin insert into audita values ( concat ( 'Actualizacion realizada por ', user(), ' el dia ', now(), '. Anteriores valores: "', old.numce, '", "', old.nomce, '" y "', old.seas, '"', '. Nuevos valores: "', new.numce, '", "', new.nomce, '" y "', new.seas, '"' ) ); end $$ delimiter ; -- Trigger C: Audita las operaciones de borrado. delimiter $$ create trigger t_aud_borrado after delete on centros for each row begin insert into audita values ( concat ( 'Fila borrada por ', user(), ' el dia ', now(), '. Valores borrados: "', old.numce, '", "', old.nomce, '" y "', old.seas, '"' ) ); end $$ delimiter ; |
1×25: Uso de Triggers con insert, update y delete
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
/* Ejercicio 25: Realizar dos triggers que completen la funcionalidad del trigger1 del apartado 9.3 de los materiales, mantener sincronizada la tabla alumnos_replica, pero para las operaciones de modificación (trigger ejercicio25a) y borrado (trigger ejercicio25b). */ /* Un trigger es un programa almacenado que no se ejecuta por voluntad del usuario, si no que se ejecuta solo de forma automática cuando se realizan modificaciones con las sentencias: insert, update y delete. Podemos elegir cuando se ha de ejecutar el trigger, si antes (before) de realizar la acción o después (after). El trigger solo funciona bajo la tabla que especifiquemos y cada tabla como máximo podrá tener 6 trigger, 2 por cada sentencia. Notas de interes: Muestra los triggers: show triggers; Borra un trigger: drop trigger t_copia; */ -- Primero se copia una tabla para hacer las pruebas: create table alumnos_replica (select * from alumnos); -- Triger 1: Se encarga de sincronizar las nuevas filas insertadas: delimiter $$ create trigger t_copia before insert on alumnos for each row begin -- Disponemos de "new" para obtener el nuevo valor en insert y update -- y de "old" para obtener el valor anterior en update y delete. insert into alumnos_replica values (new.id, new.alumno); end $$ delimiter; -- Triger A: Mantiene las filas actualizadas: delimiter $$ create trigger t_modifica before update on alumnos for each row begin update alumnos_replica set id = new.id, alumno = new.alumno where id = old.id; end $$ delimiter ; -- Triger B: Borra las filas delimiter $$ create trigger t_borra before delete on alumnos for each row begin delete from alumnos_replica where id = old.id; end $$ delimiter ; |
1×23-24: Funciones
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
/* Ejercicio 23: Desarrollar una función que devuelva un 1 si el número de departamento que se le pasa como argumento existe y devuelva 0 en caso contrario. */ delimiter $$ drop function if exists 1x23 $$ create function 1x23(dep int) returns boolean begin if (select numde from departamentos where numde = dep) = dep then return true; else return false; end if; end $$ delimiter ; -- select 1x23(112) as 'Resultado'; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
/* Ejercicio 24: Desarrollar una función que devuelva la suma total de salarios de los empleados del número de departamento que se le pasa como argumento. Si el Departamento no existe devolverá -1. Utiliza una llamada a la función del ejercicio anterior dentro del código. */ delimiter $$ drop function if exists 1x24 $$ create function 1x24(dep int) returns int begin if (select 1x23(dep)) then return (select sum(salario) from empleados where numde = dep); else return -1; end if; end $$ delimiter ; -- select 1x24(112) as 'Total'; |