Đúng; hãy xem những gì chúng tôi có ở đây.
Đầu tiên, mã phải bị chặn như sau:
variable declarations
cursor declarations
handler declarations
everything else
Vì vậy, DECLARE CURSOR c2
của bạn phải xuất hiện giữa DECLARE CURSOR c1
và DECLARE CONTINUE HANDLER
. Ngoài ra, bạn chỉ cần một CONTINUE HANDLER
bởi vì nó có hiệu lực từ thời điểm khai báo cho đến khi kết thúc thủ tục.
Tiếp theo là câu lệnh
INSERT INTO ip_ER_subtotal
SELECT Starting_Pitcher, Game_Date, Game_Number, innings_pitched, 0.0
FROM starting_pitchers_game_log;
Các cột được đặt tên trong SELECT
mệnh đề là các cột bạn đang chọn, không những cái bạn đang chèn vào, vì vậy chúng phải là các cột trong bảng starting_pitchers_game_log
. Ngoài ra, vì các cột không được sao chép từ starting_pitchers_game_log
(nghĩa là, ip_total
, er_total
và era
) tất cả đều có giá trị mặc định, bạn có thể sử dụng danh sách cột trên INSERT
tuyên bố, như vậy:
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;
Điều này giúp tiết kiệm việc nhập, tài liệu mà các cột bạn đang thực sự chèn giá trị vào và cách ly INSERT
của bạn câu lệnh từ thứ tự vật lý của các cột trong bảng nguồn và bảng đích.
Tiếp theo, khi bạn hoàn thành CURSOR c1
vòng lặp, không cắt ngắn bảng hoặc bạn sẽ mất tất cả công việc bạn vừa làm! TRUNCATE TABLE
xóa tất cả các hàng hiện có trong bảng và được sử dụng ở đây để xóa kết quả của lần chạy trước đó.
Cuối cùng, hai vòng lặp phải có các nhãn khác nhau, chẳng hạn như fetch_loop_1
và fetch_loop_2
. Bạn cũng cần đặt lại accum
và end_of_cursor
trước khi vào vòng lặp thứ hai. Tuy nhiên, trong trường hợp này, tôi tin rằng chúng ta có thể thực hiện mọi thứ trong một vòng lặp với một con trỏ, điều này làm cho mã đơn giản hơn và do đó dễ bảo trì hơn.
Đây là quy trình hoàn chỉnh:
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 ;
Điều đó sẽ thực hiện công việc. Nếu có ai đó tìm thấy lỗi, xin vui lòng chỉ ra.
CHỈNH SỬA:Tôi vừa thêm một số mã để minh họa cách bảo vệ khỏi các giá trị rỗng đến từ bảng nguồn và cách tránh chia hết cho 0 trong phép tính ERA.
CHỈNH SỬA:Tôi đã thay đổi lại tên cột và bảng ban đầu của mình để giảm sự nhầm lẫn của chính tôi.
CHỈNH SỬA:Mã đã thay đổi để phù hợp với câu trả lời cho Làm cách nào để thêm cột vào bảng công việc bằng thủ tục mới được lưu trữ