右;ここにあるものを見てみましょう。
まず、コードを次のようにブロックする必要があります。
variable declarations
cursor declarations
handler declarations
everything else
つまり、DECLARE CURSOR c2
必須 DECLARE CURSOR c1
の間に表示されます およびDECLARE CONTINUE HANDLER
。また、必要なCONTINUE HANDLER
は1つだけです。 宣言の時点から手順の最後まで有効になるためです。
次はステートメントです
INSERT INTO ip_ER_subtotal
SELECT Starting_Pitcher, Game_Date, Game_Number, innings_pitched, 0.0
FROM starting_pitchers_game_log;
SELECT
の名前付き列 句は、選択する列です。 ない 挿入しているもの したがって、テーブルstarting_pitchers_game_log
の列である必要があります。 。また、列がstarting_pitchers_game_log
からコピーされていないため (つまり、ip_total
、er_total
およびera
)すべてデフォルト値があり、INSERT
で列リストを使用できます そのような声明:
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;
これにより、入力が節約され、実際に値を挿入している列が文書化され、INSERT
が分離されます。 ソーステーブルとターゲットテーブルの列の物理的な順序からのステートメント。
次に、CURSOR c1
を終了したら ループ、テーブルを切り捨てないでください または、今行ったすべての作業が失われます。 TRUNCATE TABLE
現在テーブルにあるすべての行を削除し、前の実行の結果をクリアするためにここで使用されます。
最後に、2つのループには異なるラベルを付ける必要があります(例:fetch_loop_1
)。 およびfetch_loop_2
。また、accum
をリセットする必要があります およびend_of_cursor
2番目のループに入る前。ただし、この場合、1つのカーソルですべてを1つのループで実行できるため、コードが単純になり、保守が容易になると思います。
完全な手順は次のとおりです。
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 ;
それでうまくいくはずです。誰かがバグを見つけたら、ぜひ指摘してください。
編集:ソーステーブルからのヌルから保護する方法と、ERA計算でゼロ除算を回避する方法を説明するコードを追加しました。
編集:自分の混乱を減らすために、元の列とテーブルの名前に戻しました。
編集:コードが変更され、新しいストアドプロシージャを使用して列を作業テーブルに追加するにはどうすればよいですか