Rechts; laten we eens kijken wat we hier hebben.
Eerst moet de code als volgt worden geblokkeerd:
variable declarations
cursor declarations
handler declarations
everything else
Dus uw DECLARE CURSOR c2
moet verschijnen tussen DECLARE CURSOR c1
en DECLARE CONTINUE HANDLER
. Je hebt ook maar één CONTINUE HANDLER
. nodig omdat het van kracht wordt vanaf het moment van aangifte tot het einde van de procedure.
Het volgende is de verklaring
INSERT INTO ip_ER_subtotal
SELECT Starting_Pitcher, Game_Date, Game_Number, innings_pitched, 0.0
FROM starting_pitchers_game_log;
De benoemde kolommen in de SELECT
clausule zijn de kolommen waaruit u selecteert, niet degene die u invoegt, dus het moeten kolommen zijn in de tabel starting_pitchers_game_log
. Omdat de kolommen niet worden gekopieerd uit starting_pitchers_game_log
(dat wil zeggen, ip_total
, er_total
en era
) hebben allemaal standaardwaarden, u kunt een kolomlijst gebruiken op de INSERT
verklaring, zoals zo:
INSERT INTO pitcher_stats_temp
(Starting_Pitcher, Game_Date, Game_Number, innings_pitched, er)
SELECT pitcher_id, game_date, game_seq, innings_pitched, runs
FROM starting_pitchers_game_log;
Dit bespaart typen, documenteert in welke kolommen u daadwerkelijk waarden invoegt en isoleert uw INSERT
verklaring van de fysieke volgorde van kolommen in de bron- en doeltabellen.
Vervolgens, als u klaar bent met de CURSOR c1
loop, kort de tabel niet af of je verliest al het werk dat je net hebt gedaan! TRUNCATE TABLE
verwijdert alle rijen die momenteel in de tabel staan en wordt hier gebruikt om de resultaten van de vorige run te wissen.
Ten slotte moeten de twee lussen verschillende labels hebben, zeg fetch_loop_1
en fetch_loop_2
. U moet ook accum
. resetten en end_of_cursor
voordat u de tweede lus ingaat. In dit geval geloof ik echter dat we alles in één lus kunnen doen met één cursor, wat de code eenvoudiger en dus gemakkelijker te onderhouden maakt.
Hier is de volledige procedure:
DROP PROCEDURE IF EXISTS pitcher_stats_era;
DELIMITER $$
CREATE PROCEDURE pitcher_stats_era()
BEGIN
DECLARE pit_id CHAR(10);
DECLARE gdate DATE;
DECLARE seq INT;
DECLARE in_pit REAL;
DECLARE er INT;
DECLARE accum_ip REAL;
DECLARE accum_er INT;
DECLARE earned_run_avg REAL;
DECLARE prev_year YEAR(4);
DECLARE end_of_cursor BOOLEAN;
DECLARE no_table CONDITION FOR SQLSTATE '42S02';
DECLARE c1 CURSOR FOR
SELECT pitcher_id, game_date, game_seq, innings_pitched, earned_runs
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;
------------------------------------------------------------------
-- The following steps are now performed by pitcher_stats_reset()
------------------------------------------------------------------
-- TRUNCATE TABLE ip_subtotal; -- Clear our work table for a new run
-- Copy data from main table into work table
-- INSERT INTO ip_subtotal
-- (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;
---------------------------------------------------------------------
SET end_of_cursor := FALSE; -- reset
SET prev_year := 0; -- reset control-break
OPEN c1;
fetch_loop: LOOP
FETCH c1 INTO pit_id, gdate, seq, in_pit, er;
IF end_of_cursor THEN
LEAVE fetch_loop;
END IF;
-- check control-break conditions
IF YEAR(gdate) != prev_year THEN
SET accum_ip := 0.0;
SET accum_er := 0;
SET prev_year := YEAR(gdate);
END IF;
SET accum_ip := accum_ip + in_pit;
SET accum_er := accum_er + er;
IF accum_er = 0 THEN -- prevent divide-by-zero
SET earned_run_avg := 0;
ELSE
SET earned_run_avg := (accum_ip / accum_er) * 9;
END IF;
UPDATE pitcher_stats_temp
SET ip_total = accum_ip,
er_total = accum_er,
std_era = earned_run_avg
WHERE pitcher_id = pit_id
AND game_date = gdate
AND game_seq = seq;
END LOOP;
CLOSE c1;
END
$$
DELIMITER ;
Dat zou het werk moeten doen. Als iemand een bug vindt, wijs hem dan vooral.
EDIT:ik heb zojuist wat code toegevoegd om te illustreren hoe te beschermen tegen nulls afkomstig van de brontabel en hoe een deel door nul op de ERA-berekening te voorkomen.
EDIT:ik heb mijn oorspronkelijke kolom- en tabelnamen teruggezet om mijn eigen verwarring te verminderen.
EDIT:Code gewijzigd om consistent te zijn met het antwoord op Hoe kan ik een kolom toevoegen aan een werktabel met behulp van een nieuwe opgeslagen procedure