Esta pregunta y su respuesta se basan en las respuestas a ¿Cómo puedo combinar dos procedimientos en uno para completar una tabla en lugar de que cada uno de los dos procedimientos complete su propia tabla? y ¿Cómo puedo agregar una columna que se incrementa en otra columna en la misma tabla? , y la respuesta a esta pregunta requiere cambios menores a la respuesta a las dos anteriores, que señalaré cuando corresponda.
Dado que los cálculos del "período de descanso del lanzador" y el "promedio de carreras ganadas" son independientes entre sí, recomiendo un procedimiento separado para cada uno. Sin embargo, dado que los resultados de los dos procedimientos a menudo se usarán juntos, recomiendo una tabla común para los cálculos y sugiero refactorización la creación y población de esa tabla temporal en un tercer procedimiento:
DELIMITER $$
-- DROP PROCEDURE pitcher_stats_reset $$
CREATE PROCEDURE pitcher_stats_reset()
BEGIN
DROP TEMPORARY TABLE IF EXISTS pitcher_stats_temp;
CREATE TEMPORARY TABLE pitcher_stats_temp
(
pitcher_id char(10) NOT NULL,
game_date date NOT NULL,
game_seq int NOT NULL,
innings_pitched double DEFAULT 0.0,
ip_total double DEFAULT 0.0,
earned_runs INT DEFAULT 0,
er_total INT DEFAULT 0,
std_era DOUBLE DEFAULT 0.0,
starter_rest INT DEFAULT 0,
CONSTRAINT pitcher_stats_temp_pk
PRIMARY KEY (pitcher_id , game_date , game_seq )
) ENGINE=InnoDB;
INSERT INTO pitcher_stats_temp
(pitcher_id, game_date, game_seq, innings_pitched, earned_runs)
SELECT pitcher_id, game_date, game_seq,
IFNULL(innings_pitched, 0), -- replace NULL with 0, if
IFNULL(runs, 0) -- column not initialized
FROM starting_pitchers_game_log;
END $$
DELIMITER ;
La versión anterior usaba una tabla persistente normal porque aún no estaba familiarizado con el manejo de tablas temporales de MySQL. Una tabla temporal se elimina automáticamente cuando el usuario cierra la sesión, recuperando el espacio utilizado para los datos derivados que se pueden regenerar según sea necesario. Descartar y volver a crear la tabla es equivalente a TRUNCATE
ing (excepto que la tabla no necesita existir de antemano) que a su vez es mucho más rápido que un DELETE
incondicional , de acuerdo con los documentos de MySQL. Realicé los cambios anotados apropiados en procedimiento de promedio de carreras ganadas
también.
El procedimiento para calcular el tiempo de descanso de los lanzadores una vez más sigue el lenguaje estándar de "control-descanso". Tenga en cuenta que leemos el primer registro y configuramos los campos de control una vez antes de ingresar al bucle, luego dentro del bucle probamos nuestra condición de salida, procesamos el registro "actual", leemos el registro "siguiente" y hacemos un bucle.
DROP PROCEDURE IF EXISTS pitcher_stats_rest_time;
DELIMITER $$
CREATE PROCEDURE pitcher_stats_rest_time()
BEGIN
DECLARE pit_id CHAR(10);
DECLARE prev_pit CHAR(10);
DECLARE gdate DATE;
DECLARE seq INT;
DECLARE prev_date DATE;
DECLARE rest_days INT;
DECLARE end_of_cursor BOOLEAN;
DECLARE no_table CONDITION FOR SQLSTATE '42S02';
DECLARE c1 CURSOR FOR
SELECT pitcher_id, game_date, game_seq
FROM pitcher_stats_temp
ORDER BY pitcher_id, game_date, game_seq;
DECLARE CONTINUE HANDLER FOR NOT FOUND
SET end_of_cursor := TRUE;
DECLARE EXIT HANDLER FOR no_table
BEGIN
SIGNAL no_table
SET MESSAGE_TEXT = "Work table not initialized. Please call pitcher_stats_reset() before continuing",
MYSQL_ERRNO = 1146;
END;
SET end_of_cursor := FALSE;
-- Read first record and initialize control fields
OPEN c1;
FETCH c1 INTO pit_id, gdate, seq;
SET prev_date := 0;
SET prev_pit := pit_id;
fetch_loop: LOOP
-- Test for end-of-cursor
IF end_of_cursor THEN
LEAVE fetch_loop;
END IF;
-- Test for change in control fields. If the pitcher changes,
-- fake a change in the year to trigger the break.
IF pit_id != prev_pit THEN
SET prev_date := 0;
END IF;
IF YEAR(prev_date) = YEAR(gdate) THEN
SET rest_days := DATEDIFF(gdate, prev_date);
ELSE
SET rest_days := 0;
END IF;
UPDATE pitcher_stats_temp
SET starter_rest = rest_days
WHERE pitcher_id = pit_id
AND game_date = gdate
AND game_seq = seq;
-- After processing record, update control fields
SET prev_date := gdate;
SET prev_pit := pit_id;
-- Read next record and repeat
FETCH c1 INTO pit_id, gdate, seq;
END LOOP;
CLOSE c1;
END $$
DELIMITER ;
En uso, pitcher_stats_reset()
se llama primero, para inicializar la mesa de trabajo. Una vez hecho esto, pitcher_stats_era()
y pitcher_stats_rest_time()
puede ser llamado repetidamente en cualquier orden. Si pitcher_stats_reset()
no se llama primero, los otros dos procedimientos emitirán un recordatorio cortés para hacerlo.