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 |
/* Pregunta 3 Realizar una función pregunta3 que calcule y devuelva el importe total de un pedido que se le pase como parámetro. La función devolverá -1 si no existe el pedido pasado como argumento. */ delimiter $$ drop function if exists 2x03 $$ create function 2x03(ped int) returns double begin if (select true from pedidos where num_pedido = ped) then return ( select sum(a.precio_unidad * d.unidades) from articulos a, detalle_pedidos d where a.cod_articulo = d.cod_articulo and d.cod_pedido = ped )- ( select descuento from pedidos where num_pedido = ped ); else return -1; end if; end $$ delimiter ; -- select 2x03(43) as 'Total'; |
Día: 15 de mayo de 2012
2×02: Trigger de borrado y actualización en cascada
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; |
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; |