我尝试使用新过程向工作表添加一个新过程,该过程与我用于填充工作表中已有的列的过程不同。我不确定这样做是否会更有效和节省资源,或者通过添加我用于填充表中已有的列/值的原始过程。在任何情况下,这是添加此列的单独过程的代码。该列被称为" starter_rest"并表示为字段中的日期值与#34; Game_Date"之间的差异。和该字段/列中的先前值。
以下是我使用的代码,它给了我一个错误。
DROP PROCEDURE IF EXTSTS accumpts_starter_rest()
DELIMITER $$
CREATE PROCEDURE accumulate_starter_rest()
BEGIN
DECLARE pit_id VARCHAR(8);
DECLARE gdate DATE;
DECLARE prev_date DATE;
DECLARE seq INT;
DECLARE strt_rst REAL;
DECLARE prev_year YEAR(4);
DECLARE end_of_cursor BOOLEAN;
DECLARE c1 CURSOR FOR
SELECT starter_rest
FROM ip_ER_ERA_subtotal_1
ORDER BY Starting_Pitcher, Game_Date, Game_Number;
DECLARE CONTINUE HANDLER FOR NOT FOUND
SET end_of_cursor := TRUE;
TRUNCATE TABLE ip_ER_ERA_subtotal_1;
INSERT INTO ip_ER_ERA_subtotal_1 (starter_rest)
SELECT starter_rest
FROM ip_ER_ERA_subtotal_1;
SET end_of_cursor := FALSE;
SET prev_year := 0;
OPEN c1;
fetch_loop: LOOP
FETCH c1 INTO pit_id, gdate, prev_date, seq, strt_rst;
IF end_of_cursor THEN
LEAVE fetch_loop;
END IF;
IF YEAR(gdate) != prev_year THEN
SET strt_rst := 0;
SET prev_year := YEAR(gdate);
END IF;
SET strt_rst := gdate - prev_date;
END IF;
UPDATE TABLE ip_ER_ERA_subtotal_1
SET starter_rest = strt_rst
WHERE Starting_Pitcher = pit_id
AND Game_Date = gdate
AND Game_Number = seq;
END LOOP;
CLOSE c1;
END
$$
这是我得到的错误:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'IF;
UPDATE TABLE ip_ER_ERA_subtotal_1
SET starter_rest = str' at line 39
这是表格的屏幕截图,其中列I'尝试填充已经创建的并且使用" NULL"值。
提前感谢您的帮助。
更新
ALTER TABLE retrosheet.starting_pitcher_game_log ADD COLUMN starter_rest INT;
UPDATE retrosheet.starting_pitcher_game_log AS b,
retrosheet.game AS g
SELECT @prev as previous,
Game_Date
FROM retrosheet.starting_pitcher_game_log
SET b. starter_rest = Game_date-@prev
WHERE b.`Game_ID` = g.`GAME_ID`
收到错误:
[ERROR in query 2] You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SELECT @prev as previous,
Game_Date
FROM retrosheet.starting_pitcher_game_log
S' at line 3
提前谢谢。
更新:这里是编辑过的表,用于在新年开始时为starter_rest设置0值:
DROP PROCEDURE IF EXISTS starting_pitcher_stats_rest_time;
DELIMITER $$
CREATE PROCEDURE starting_pitcher_stats_rest_time()
BEGIN
DECLARE pit_id CHAR(10);
DECLARE gdate DATE;
DECLARE seq INT;
DECLARE prev_date DATE;
DECLARE rest_days INT;
DECLARE prev_year YEAR(4);
DECLARE end_of_cursor BOOLEAN;
DECLARE no_table CONDITION FOR SQLSTATE '42S02';
DECLARE c1 CURSOR FOR
SELECT Starting_Pitcher, Game_Date, Game_Number
FROM starting_pitcher_stats
ORDER BY Starting_Pitcher, Game_Date, Game_Number;
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 prev_date := 0;
SET end_of_cursor := FALSE;
OPEN c1;
fetch_loop: LOOP
FETCH c1 INTO pit_id, gdate, seq;
IF end_of_cursor THEN
LEAVE fetch_loop;
END IF;
IF YEAR(gdate) != prev_year THEN
SET rest_days := 0;
SET prev_date := 0;
SET gdate := 0;
SET prev_year := YEAR(gdate);
END IF;
IF prev_date = 0 THEN
SET rest_days := 0;
ELSE
SET rest_days := DATEDIFF(gdate, prev_date);
END IF;
SET prev_date := gdate;
UPDATE starting_pitcher_stats
SET starter_rest = rest_days
WHERE Starting_Pitcher = pit_id
AND Game_Date = gdate
AND Game_Number = seq;
END LOOP;
CLOSE c1;
END
$$
DELIMITER ;
这是该表的屏幕截图,显示了新赛季开始时首发休息的超值。理想情况下,它只会重置为0:
任何帮助都会很棒。顺便问一下,达尔文,谢谢你 - 你的帮助很棒!
答案 0 :(得分:1)
这个问题及其答案建立在How can I combine two procedures in one to populate one table rather than each of the two procedures populating it's own table?和How can I add a column that increments on another column in same table?的答案之上,而这个问题的答案需要对前两个问题的答案进行微小的修改,我将在适当的时候注意到
由于“投手休息期”和“赢得的平均值”计算是相互独立的,我建议为每个计算单独的程序。但是,由于这两个过程的结果通常会一起使用,我建议使用一个通用的临时表进行计算,并建议refactoring将该临时表的创建和填充到第三个过程中:
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 ;
之前的版本使用了普通的持久表,因为我还不熟悉MySQL对临时表的处理。当用户注销时,会自动删除临时表,回收用于派生数据的空间,可以根据需要重新生成。根据MySQL文档,删除和重新创建表相当于TRUNCATE
(除了事先不需要存在表),这反过来比无条件DELETE
快得多。我也对earned-runs-average procedure进行了适当的注释更改。
计算投手休息时间的程序再次遵循标准的“控制 - 休息”习惯。请注意,我们在进入循环之前读取第一条记录并设置控制字段一次,然后在循环内我们测试退出条件,处理“当前”记录,读取“下一条”记录,然后循环。
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 ;
在使用中,首先调用pitcher_stats_reset()
来初始化工作表。完成后,可以按任何顺序重复调用pitcher_stats_era()
和pitcher_stats_rest_time()
。如果未首先调用pitcher_stats_reset()
,则其他两个程序将发出礼貌提醒。