Está en la página 1de 11

Función

Propósito

Elaborar una función con un parámetro de entrada, que debe ser de tipo Entero y
cuyo posible dato debe existir en la columna film_id de la tabla film, la cual debe
retornar: quienes han alquilado la película, nombre_persona, fecha_renta,
fecha_devolucion.

Solución propuesta 1 – Sin JSON


Sentencia SQL

DROP FUNCTION IF EXISTS alquiler_pelicula_persona;

DELIMITER $$
# Inicio - Bloque de creacion
USE SAKILA $$
CREATE FUNCTION alquiler_pelicula_persona (v_film_id SMALLINT)
RETURNS TEXT
DETERMINISTIC
# Fin - Bloque de creacion
# Inicio - Bloque de implementacion
BEGIN
SET @datos = (SELECT GROUP_CONCAT(f.datos)
FROM (
SELECT CONCAT(f.title,',',c.first_name,'
',c.last_name,',',r.rental_date,',',r.return_date,'|') datos
FROM sakila.film f
INNER JOIN sakila.inventory i
ON (f.film_id = i.film_id)
INNER JOIN sakila.rental r
ON (i.inventory_id = r.inventory_id)
INNER JOIN sakila.customer c
ON (r.customer_id = c.customer_id)
WHERE f.film_id = v_film_id
GROUP BY f.title, c.first_name, c.last_name, r.rental_date,
r.return_date, c.customer_id
) f);
RETURN @datos;
END $$
# Fin - Bloque de implementacion
DELIMITER ;

Sección de pruebas
SET @rentas = alquiler_pelicula_persona(1);
SELECT @rentas;
Explicación

Para conocer cómo se relacionan las entidades entre sí dentro del sistema, fue
necesario revisar previamente el Diagrama Entidad - Relación, para así definir los
valores de entrada, llamando la función y utilizando un subquery con varios INNER
JOIN y se obtuvo los datos específicos vinculados en una tupla, esta queda
asociada a la variable datos, que fue la variable que se retornó, el tipo de dato
utilizado fue texto, ya que permite guardar cadenas de caracteres grandes como lo
precisa el ejercicio.

Resultado

Solución propuesta 2 – Con JSON


Sentencia SQL

DELIMITER $$
# Inicio - Bloque de creacion
USE SAKILA $$
CREATE FUNCTION alquiler_pelicula_persona_arr (v_film_id SMALLINT)
RETURNS JSON
DETERMINISTIC
# Fin - Bloque de creacion
# Inicio - Bloque de implementacion
BEGIN
RETURN (
SELECT JSON_ARRAYAGG(f_d.datos) json_array
FROM (
SELECT JSON_OBJECT(f.title,CONCAT(c.first_name,'
',c.last_name),r.rental_date,r.return_date) datos
FROM sakila.film f
INNER JOIN sakila.inventory i
ON (f.film_id = i.film_id)
INNER JOIN sakila.rental r
ON (i.inventory_id = r.inventory_id)
INNER JOIN sakila.customer c
ON (r.customer_id = c.customer_id)
WHERE f.film_id = v_film_id
GROUP BY f.title, c.first_name, c.last_name, r.rental_date,
r.return_date, c.customer_id
) f_d
);
END $$
# Fin - Bloque de implementacion
DELIMITER ;

Sección de pruebas
SET @rentas = alquiler_pelicula_persona_arr (1);
SELECT JSON_EXTRACT(@rentas, '$[1]'); # Obtener primer elemento

Explicación

Para el desarrollo de esta función se buscó un Array SQL como resultado, se utilizó
la misma lógica implementada en el desarrollo anterior con la diferencia que aquí se
implementó una variable de tipo de JSON que tiene funcionamiento de un arreglo, el
cual permite escoger posiciones específicas.

Resultado
Procedimiento almacenado

Propósito
Realizar un procedimiento que tenga como parámetros lo siguiente:

 Variable de entrada que debe existir en la columna film_id de la tabla film,


de tipo IN
 Variable para asignar número de veces que se rentó una película, de tipo
INOUT
 Variable para registrar los actores que participaron en la película, de tipo
OUT

Solución propuesta
Sentencia SQL

DROP PROCEDURE IF EXISTS actores_peliculas;


DELIMITER $$
# Inicio - Bloque de creacion
USE SAKILA $$
CREATE PROCEDURE actores_peliculas(IN v_film_id SMALLINT, INOUT
v_cantidad_rentas INT, OUT v_actores TEXT)
# Fin - Bloque de creacion
# Inicio - Bloque de implementacion
BEGIN
SET v_cantidad_rentas = v_cantidad_rentas +
JSON_LENGTH(alquiler_pelicula_persona_arr(v_film_id));

SELECT CONCAT('[',GROUP_CONCAT(f_a.actor_nombre),']')
INTO v_actores
FROM (
SELECT CONCAT(a.first_name,' ',a.last_name) actor_nombre
FROM sakila.film f
INNER JOIN sakila.film_actor fa
ON (f.film_id = fa.film_id)
INNER JOIN sakila.actor a
ON (fa.actor_id = a.actor_id)
WHERE f.film_id = v_film_id
) f_a;

END $$
# Fin - Bloque de implementacion
DELIMITER ;

Sección de pruebas
SET @cantidad_rentas = 0;
CALL actores_peliculas(1, @cantidad_rentas, @actores);
SELECT @cantidad_rentas, @actores;

Explicación
Se definen los parámetros de entrada en base a los requisitos establecidos,
posterior a esto se asigna el valor de la cantidad de la cantidad de veces que se
rentó una película (variable v_film_id) a la variable v_cantidad_rentas, para ello se
hace uso de la función JSON_LENGTH, función integrada de MySQL para retornar
el tamaño de una variable tipo JSON, que obtendrá el tamaño del valor retornado
por la función creada en la sección anterior.

Realizado lo anterior, se realiza una consulta a las tablas film, film_actor y actor,
haciendo un cruce entre las tres para identificar los actores que han participado en
la película ingresada.

Resultado:
Trigger

Propósito
Definir una columna nueva en la tabla store de tipo numérica INT, que debe ser
mayor a cero y cuyo nombre sea num_empleados, que deberá contener el número
de empleados asociados por tienda. Cuando se inserte una nueva tienda a la tabla
store se debe disparar una inserción de datos aleatorios en la tabla staff, simulando
la contratación de los empleados necesarios para la tienda.

Agregar columna num_empleados


ALTER TABLE sakila.store
ADD COLUMN num_empleados SMALLINT SIGNED;

Solución propuesta – Inserción


Sentencia SQL
DROP TRIGGER IF EXISTS staff_insertar;

DELIMITER $$
CREATE TRIGGER staff_insertar AFTER INSERT ON sakila.store FOR EACH ROW
# Inicio - Bloque de implementacion
BEGIN
IF NEW.num_empleados IS NOT NULL AND NEW.num_empleados > 1 THEN # Se
insertan valores si no es nulo o si es mayor a uno diferente del
administrador
SET @nombre_array =
JSON_ARRAY('Raul','Gabriel','Maria','Natalia','Sara');
SET @apellido_array =
JSON_ARRAY('Garcia','Bustamante','Hernandez','Cruz','Santonilli');
SET @password_array =
JSON_ARRAY('12435','54321','11111','22222','33333');
SET @i = 1;
insertar: LOOP
SET @i = @i + 1;
SET @temp_nombre = JSON_EXTRACT(@nombre_array, CONCAT('$
[',FLOOR(RAND()*(JSON_LENGTH(@nombre_array)-1+1)),']'));

INSERT INTO sakila.staff


(staff_id, first_name, last_name, address_id, picture,
email, store_id, active, username, password, last_update)
VALUES (NULL,
@temp_nombre,
JSON_EXTRACT(@apellido_array, CONCAT('$
[',FLOOR(RAND()*(JSON_LENGTH(@apellido_array)-1+1)),']')),
1,
NULL,
NULL,
NEW.store_id,
1,
@temp_nombre,
JSON_EXTRACT(@password_array, CONCAT('$
[',FLOOR(RAND()*(JSON_LENGTH(@password_array)-1+1)),']')),
SYSDATE());
IF @i <= NEW.num_empleados THEN
ITERATE insertar;
END IF;
LEAVE insertar;
END LOOP insertar;
END IF;
END $$
# Fin - Bloque de implementacion
DELIMITER ;

Explicación
Se define el disparador como tipo INSERT para que el disparador se active después
de la inserción de una fila. Se crean tres variables que contendrán datos por defecto
para el nombre, apellido y password; las cuales serán ingresadas en la tabla staff.
Posterior a esto se crea el ciclo “insertar”, en el cual se ingresarán los datos fila a fila
en la columna staff.

Solución propuesta – Actualizar


Sentencia SQL
DROP TRIGGER IF EXISTS staff_actualizar;

DELIMITER $$
CREATE TRIGGER staff_actualizar BEFORE UPDATE ON sakila.store FOR EACH ROW
# Inicio - Bloque de implementacion
BEGIN
#SET @var_num_emp_prev = 0;

#IF NEW.num_empleados <> @var_num_emp_prev AND NEW.num_empleados > 1


THEN # El administrador no sera eliminado
IF NEW.num_empleados <> OLD.num_empleados AND NEW.num_empleados >= 1
THEN # El administrador no sera eliminado
# Eliminar staff
#IF NEW.num_empleados < @var_num_emp_prev THEN
IF NEW.num_empleados < OLD.num_empleados THEN
SET @i = OLD.num_empleados;
eliminar: LOOP
SET @i = @i - 1;
SET @id_staff_eliminar = 0;

SELECT s.staff_id
INTO @id_staff_eliminar
FROM sakila.staff s
WHERE s.store_id = NEW.store_id
#AND s.staff_id <> NEW.manager_staff_id
AND NOT EXISTS (SELECT 1 FROM sakila.store WHERE
manager_staff_id = s.staff_id)
LIMIT 1;

DELETE FROM sakila.staff


WHERE staff_id = @id_staff_eliminar;

IF @i > NEW.num_empleados THEN


ITERATE eliminar;
END IF;
LEAVE eliminar;
END LOOP eliminar;
ELSE
# Insertar staff
SET @nombre_array =
JSON_ARRAY('Raul','Gabriel','Maria','Natalia','Sara');
SET @apellido_array =
JSON_ARRAY('Garcia','Bustamante','Hernandez','Cruz','Santonilli');
SET @password_array =
JSON_ARRAY('12435','54321','11111','22222','33333');
SET @i = OLD.num_empleados;
insertar: LOOP
SET @i = @i + 1;
SET @temp_nombre = JSON_EXTRACT(@nombre_array, CONCAT('$
[',FLOOR(RAND()*(JSON_LENGTH(@nombre_array)-1+1)),']'));

INSERT INTO sakila.staff


(staff_id, first_name, last_name, address_id,
picture, email, store_id, active, username, password, last_update)
VALUES (NULL,
@temp_nombre,
JSON_EXTRACT(@apellido_array, CONCAT('$
[',FLOOR(RAND()*(JSON_LENGTH(@apellido_array)-1+1)),']')),
1,
NULL,
NULL,
NEW.store_id,
1,
@temp_nombre,
JSON_EXTRACT(@password_array, CONCAT('$
[',FLOOR(RAND()*(JSON_LENGTH(@password_array)-1+1)),']')),
SYSDATE());
IF @i < NEW.num_empleados THEN
ITERATE insertar;
END IF;
LEAVE insertar;
END LOOP insertar;
END IF;
END IF;
END $$
# Fin - Bloque de implementacion
DELIMITER ;

Explicación
Se crea un disparador de tipo UPDATE, y similar al disparador anterior se realiza
una actualización a las filas según dos casos:
- Si es mayor a la cantidad de datos que tiene actualmente para el número de
empleados, se realiza la inserción de datos de la misma forma que en el
disparador de inserción.
- Si la cantidad de empleados es menor se realiza una consulta para retornar
el id de un empleado aleatorio y realizado esto, eliminarlo. Si por error la
cantidad de empleados es menor a 1, el disparador no elimina nada, ya que,
como mínimo, una tienda debe contar con un empleado, que en este caso
sería el manager de la tienda.

Solución propuesta – Actualizar versión 2


Sentencia SQL
DROP TRIGGER IF EXISTS staff_actualizar_v2;

DELIMITER $$
CREATE TRIGGER staff_actualizar_v2 BEFORE UPDATE ON sakila.store FOR EACH
ROW
# Inicio - Bloque de implementacion
BEGIN
IF NEW.num_empleados <> OLD.num_empleados AND NEW.num_empleados >= 1
THEN # El administrador no sera eliminado
# Eliminar staff
IF NEW.num_empleados < OLD.num_empleados THEN
SET @i = 0;
DELETE s FROM sakila.staff s
INNER JOIN (
SELECT staff_id
FROM (
SELECT (@i:=@i+1) num,
staff_id
FROM sakila.staff
WHERE store_id = NEW.store_id
AND staff_id NOT IN (SELECT manager_staff_id FROM
sakila.store)
) num_staff
WHERE num_staff.num <= (OLD.num_empleados-
NEW.num_empleados)
) filtro
ON (filtro.staff_id = s.staff_id);
ELSE
# Insertar staff
SET @nombre_array =
JSON_ARRAY('Raul','Gabriel','Maria','Natalia','Sara');
SET @apellido_array =
JSON_ARRAY('Garcia','Bustamante','Hernandez','Cruz','Santonilli');
SET @password_array =
JSON_ARRAY('12435','54321','11111','22222','33333');
SET @i = OLD.num_empleados;
insertar: LOOP
SET @i = @i + 1;
SET @temp_nombre = JSON_EXTRACT(@nombre_array, CONCAT('$
[',FLOOR(RAND()*(JSON_LENGTH(@nombre_array)-1+1)),']'));

INSERT INTO sakila.staff


(staff_id, first_name, last_name, address_id,
picture, email, store_id, active, username, password, last_update)
VALUES (NULL,
@temp_nombre,
JSON_EXTRACT(@apellido_array, CONCAT('$
[',FLOOR(RAND()*(JSON_LENGTH(@apellido_array)-1+1)),']')),
1,
NULL,
NULL,
NEW.store_id,
1,
@temp_nombre,
JSON_EXTRACT(@password_array, CONCAT('$
[',FLOOR(RAND()*(JSON_LENGTH(@password_array)-1+1)),']')),
SYSDATE());
IF @i < NEW.num_empleados THEN
ITERATE insertar;
END IF;
LEAVE insertar;
END LOOP insertar;
END IF;
END IF;
END $$
# Fin - Bloque de implementacion
DELIMITER ;

Explicación
En esta tercera opción se mantiene la lógica del disparador de actualización
previamente descrito, pero, a diferencia del anterior, en vez de realizar un proceso
de eliminación seleccionando id por id se realiza una consulta y se eliminan los
datos de la tabla staff en base al resultado de esta.

Resultado
Para las pruebas se debe tener en cuenta el estado inicial de la tabla store y staff,
por ende, se debe consultar las tablas antes de la modificación.

select * from sakila.store where store_id = 16;


select * from sakila.staff where store_id = 16;

Resultado para la tabla store

Resultado para la tabla staff


Ahora, para realizar la prueba se hará uso de una actualización, aunque también
funciona al insertar datos (una nueva tienda) a la tabla store.

UPDATE sakila.store SET num_empleados = 4 WHERE store_id = 16;

Posterior a la actualización, los resultados para las tablas store y staff son
respectivamente:

También podría gustarte