Tato otázka a její odpověď vycházejí z odpovědí na Jak mohu zkombinovat dvě procedury do jedné, aby se naplnila jedna tabulka místo toho, aby každá ze dvou procedur vyplnila svou vlastní tabulku? a Jak mohu přidat sloupec, který se zvyšuje o další sloupec ve stejné tabulce? a odpověď na tuto otázku vyžaduje drobné změny v odpovědi na předchozí dvě, které si v případě potřeby všimnu.
Vzhledem k tomu, že výpočty „doba odpočinku nad džbánem“ a „průměr získaných běhů“ jsou na sobě nezávislé, doporučuji pro každý samostatný postup. Protože však výsledky těchto dvou postupů budou často používány společně, doporučuji pro výpočty společnou stírací tabulku a navrhuji refaktorování vytvoření a naplnění této stírací tabulky do třetí procedury:
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 ;
Předchozí verze používala normální trvalou tabulku, protože jsem ještě nebyl obeznámen s tím, jak MySQL zachází s dočasnými tabulkami. Dočasná tabulka je automaticky zrušena, když se uživatel odhlásí, čímž se získá zpět místo použité pro odvozená data, která lze v případě potřeby znovu obnovit. Vypuštění a opětovné vytvoření tabulky je ekvivalentní TRUNCATE
ing (kromě toho, že tabulka nemusí existovat předem), což je zase mnohem rychlejší než bezpodmínečné DELETE
, podle dokumentů MySQL. Provedl jsem příslušné anotované změny v vydělaný-běh-průměrný postup
také.
Postup výpočtu doby odpočinku nadhazovačů se opět řídí standardním idiomem „kontrola-přestávka“. Všimněte si, že před vstupem do smyčky jednou načteme první záznam a nastavíme ovládací pole, poté v rámci smyčky otestujeme naši výstupní podmínku, zpracujeme „aktuální“ záznam, přečteme „další“ záznam a smyčku.
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 ;
Používá se pitcher_stats_reset()
se zavolá jako první, aby se inicializovala pracovní tabulka. Jakmile to uděláte, pitcher_stats_era()
a pitcher_stats_rest_time()
lze volat opakovaně v libovolném pořadí. Pokud pitcher_stats_reset()
není voláno jako první, ostatní dva postupy vydají zdvořilou připomínku, aby tak učinily.