To pytanie i odpowiedź na nie opierają się na odpowiedziach na Jak mogę połączyć dwie procedury w jedną, aby wypełnić jedną tabelę, a nie każdą z dwóch procedur wypełniających jej własną tabelę? i Jak mogę dodać kolumnę, która zwiększa się w innej kolumnie w tej samej tabeli? , a odpowiedź na to pytanie wymaga drobnych zmian w odpowiedzi na dwa poprzednie, które w razie potrzeby zaznaczę.
Ponieważ obliczenia „okresu odpoczynku w miotaczu” i „średniej uzyskanej liczby przebiegów” są od siebie niezależne, zalecam dla każdego z nich osobną procedurę. Ponieważ jednak wyniki tych dwóch procedur będą często używane razem, zalecam wspólną tabelę zdrapek do obliczeń i sugeruję refaktoryzacja utworzenie i wypełnienie tej tabeli zdrapek w trzeciej procedurze:
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 ;
Poprzednia wersja używała normalnej, trwałej tabeli, ponieważ nie byłem jeszcze zaznajomiony z obsługą tabel tymczasowych w MySQL. Tabela tymczasowa jest automatycznie usuwana, gdy użytkownik się wyloguje, odzyskując miejsce używane na dane pochodne, które można ponownie wygenerować w razie potrzeby. Upuszczenie i ponowne utworzenie tabeli jest równoważne z TRUNCATE
ing (poza tym, że tabela nie musi istnieć wcześniej), co z kolei jest znacznie szybsze niż bezwarunkowe DELETE
, zgodnie z dokumentacją MySQL. Wprowadziłem odpowiednie zmiany z adnotacjami w procedura-wypracowanych-średnia-przebiegów
również.
Procedura obliczania czasu odpoczynku miotaczy po raz kolejny jest zgodna ze standardowym idiomem „kontrola-przerwa”. Zauważ, że czytamy pierwszy rekord i ustawiamy pola kontrolne raz przed wejściem do pętli, a następnie w pętli testujemy nasz warunek wyjścia, przetwarzamy „bieżący” rekord, odczytujemy „następny” rekord i wykonujemy pętlę.
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 ;
W użyciu pitcher_stats_reset()
jest wywoływana jako pierwsza, aby zainicjować stół roboczy. Gdy to zrobisz, pitcher_stats_era()
i pitcher_stats_rest_time()
może być wywoływana wielokrotnie w dowolnej kolejności. Jeśli pitcher_stats_reset()
nie jest wywoływany jako pierwszy, pozostałe dwie procedury wystosują uprzejme przypomnienie, aby to zrobić.