I created two tables that were each populated with a different procedure in MySQL with Sequel Pro. While each table has the correct information in it after running the respective procedure, I'm thinking that my data will be less scattered tables if I consolidate some of the tables more.
So, what I would like to do is combine the data from both tables into one. Below is the code I used to try to accomplish this. Unfortunately, it didn't work, and any help with the code would be much appreciated.
create table code:
-- Table: ip_ER_ERA_subtotal
-- DROP TABLE ip_ER_ERA_subtotal;
CREATE TABLE ip_ER_ERA_subtotal
(
Starting_Pitcher VARCHAR(8) NOT NULL,
Game_Date VARCHAR (10) NOT NULL,
Game_Number VARCHAR (1) NOT NULL,
innings_pitched double,
ER double,
ip_total double DEFAULT '0.0',
ER_total double DEFAULT '0.0',
ERA double DEFAULT '0.0',
CONSTRAINT ip_ER_ERA_subtotal_pk
PRIMARY KEY (Starting_Pitcher, Game_Date , Game_Number)
) ENGINE=InnoDB
procedure code:
DELIMITER $$
CREATE PROCEDURE accumulate_IP_ER()
BEGIN
DECLARE pit_id CHAR(10);
DECLARE gdate DATE;
DECLARE seq INT;
DECLARE in_pit REAL;
DECLARE earned_runs REAL;
DECLARE accum REAL;
DECLARE prev_year YEAR(4);
DECLARE end_of_cursor BOOLEAN;
DECLARE c1 CURSOR FOR
SELECT Starting_Pitcher, Game_Date, Game_Number, innings_pitched
FROM ip_ER_subtotal
ORDER BY Starting_Pitcher, Game_Date, Game_Number;
DECLARE CONTINUE HANDLER FOR NOT FOUND
SET end_of_cursor := TRUE;
TRUNCATE TABLE ip_ER_subtotal;
INSERT INTO ip_ER_subtotal
SELECT Starting_Pitcher, Game_Date, Game_Number, innings_pitched, 0.0
FROM starting_pitchers_game_log;
SET prev_year := 0;
OPEN c1;
fetch_loop: LOOP
FETCH c1 INTO pit_id, gdate, seq, in_pit;
IF end_of_cursor THEN
LEAVE fetch_loop;
END IF;
IF YEAR(gdate) != prev_year THEN
SET accum := 0.0;
SET prev_year := YEAR(gdate);
END IF;
SET accum := accum + in_pit;
UPDATE ip_ER_subtotal
SET ip_total = accum
WHERE Starting_Pitcher = pit_id
AND Game_Date = gdate
AND Game_Number = seq;
END LOOP;
CLOSE c1;
DECLARE c2 CURSOR FOR
SELECT Starting_Pitcher, Game_Date, Game_Number, earned_runs
FROM ip_ER_subtotal
ORDER BY Starting_Pitcher, Game_Date, Game_Number;
DECLARE CONTINUE HANDLER FOR NOT FOUND
SET end_of_cursor := TRUE;
TRUNCATE TABLE ER_subtotal;
INSERT INTO ip_ER_subtotal
SELECT Starting_Pitcher, Game_Date, Game_Number, ER, 0.0
FROM starting_pitchers_game_log;
SET prev_year := 0;
OPEN c2;
fetch_loop: LOOP
FETCH c2 INTO pit_id, gdate, seq, earned_runs;
IF end_of_cursor THEN
LEAVE fetch_loop;
END IF;
IF YEAR(gdate) != prev_year THEN
SET accum := 0.0;
SET prev_year := YEAR(gdate);
END IF;
SET accum := accum + earned_runs;
UPDATE ip_ER_subtotal
SET ER_total = accum
WHERE Starting_Pitcher = pit_id
AND Game_Date = gdate
AND Game_Number = seq;
END LOOP;
CLOSE c2;
END
I get the following error:
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 'DECLARE c2 CURSOR FOR
SELECT Starting_Pitcher, Game_Date, Game_Number, e' at line 46
Here is a screenshot of the first table I already created "ip_subtotal"
Here is a screenshot of the second table I already created "ER_subtotal"
Update:
Here is essentially your same code that I made minor changes to:
DELIMITER $$
CREATE PROCEDURE accumulate_IP_ER_ERA()
BEGIN
DECLARE pit_id VARCHAR(8);
DECLARE gdate VARCHAR(10);
DECLARE seq VARCHAR(1);
DECLARE in_pit REAL;
DECLARE earned_runs 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 c1 CURSOR FOR
SELECT Starting_Pitcher, Game_Date, Game_Number, innings_pitched, ER
FROM ip_ER_ERA_subtotal
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;
INSERT INTO ip_ER_ERA_subtotal
(Starting_Pitcher, Game_Date, Game_Number, innings_pitched, ER)
SELECT Starting_Pitcher, Game_Date, Game_Number, innings_pitched, ER
FROM starting_pitcher_game_log;
SET end_of_cursor := FALSE;
SET prev_year := 0;
OPEN c1;
fetch_loop: LOOP
FETCH c1 INTO pit_id, gdate, seq, in_pit, earned_runs, accum_ip, accum_er, earned_run_avg;
IF end_of_cursor THEN
LEAVE fetch_loop;
END IF;
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;
SET earned_run_avg := (accum_er / accum_ip) * 9;
UPDATE ip_ER_ERA_subtotal
SET ip_total = accum_ip,
ER_total = accum_er,
STD_ERA = earned_run_avg
WHERE Starting_Pitcher = pit_id
AND Game_Date = gdate
AND Game_Number = seq
AND prev_year=YEAR;
END LOOP;
CLOSE c1;
END
Here's the error:
Incorrect number of FETCH variables
I did try to see what if any variables aren't being fetched and tried to add "accum_ip", "accum_er", "earned_run_avg" but it didn't work...It seems like the eight variables are the ones that the latter three + ones in your fetch statement should be the ones needed...
Here's the table code:
-- Table: ip_ER_ERA_subtotal
-- DROP TABLE ip_ER_ERA_subtotal;
CREATE TABLE ip_ER_ERA_subtotal
(
Starting_Pitcher VARCHAR(8) NOT NULL,
Game_Date VARCHAR(10) NOT NULL,
Game_Number INT(1) NOT NULL,
innings_pitched double,
ER double,
ip_total double DEFAULT '0.0',
ER_total double DEFAULT '0',
STD_ERA double DEFAULT '0.0',
CONSTRAINT ip_ER_ERA_subtotal_pk
PRIMARY KEY (Starting_Pitcher, Game_Date , Game_Number)
) ENGINE=InnoDB
update:
Here's the code based on your changes, but columns ER, ER_total, and STD_ERA are filled with only "Null" values.
DELIMITER $$
CREATE PROCEDURE accumulate_ip_ER_ERA()
BEGIN
DECLARE pit_id VARCHAR(8);
DECLARE gdate VARCHAR(10);
DECLARE seq VARCHAR(1);
DECLARE in_pit REAL;
DECLARE ER REAL;
DECLARE accum_ip REAL;
DECLARE accum_er REAL;
DECLARE earned_run_avg REAL;
DECLARE prev_year YEAR(4);
DECLARE end_of_cursor BOOLEAN;
DECLARE c1 CURSOR FOR
SELECT Starting_Pitcher, Game_Date, Game_Number, innings_pitched, ER
FROM ip_ER_ERA_subtotal
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;
INSERT INTO ip_ER_ERA_subtotal
(Starting_Pitcher, Game_Date, Game_Number, innings_pitched, ER)
SELECT Starting_Pitcher, Game_Date, Game_Number, innings_pitched, ER
FROM starting_pitcher_game_log;
SET end_of_cursor := FALSE;
SET prev_year := 0;
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;
IF YEAR(gdate) != prev_year THEN
SET accum_ip := 0.0;
SET accum_er := 0.0;
SET prev_year := YEAR(gdate);
END IF;
SET accum_ip := accum_ip + in_pit;
SET accum_er := accum_er + ER;
SET earned_run_avg := (accum_er / accum_ip) * 9;
UPDATE ip_ER_ERA_subtotal
SET ip_total = accum_ip,
ER_total = accum_er,
STD_ERA = earned_run_avg
WHERE Starting_Pitcher = pit_id
AND Game_Date = gdate
AND Game_Number = seq;
END LOOP;
CLOSE c1;
END
$$
Here's a screenshot of the table:
Could it be that only a single formula can be handled in any given cursor operation?
SET accum_ip := accum_ip + in_pit;
SET accum_er := accum_er + ER;
SET earned_run_avg := (accum_er / accum_ip) * 9
Thank you for your help.
Darwin,
Ok, here is the edited code that populates the following columns with correct values: Starting_Pitcher, Game_Date, Game_Number, innings pitched and ER from the table ip_ER_ERA_subtotal. Columns ER_total and STD_ERA have all "0"s in them.
Here is the code:
DELIMITER $$
CREATE PROCEDURE accumulate_ip_ER_ERA()
BEGIN
DECLARE pit_id VARCHAR(8);
DECLARE gdate VARCHAR(10);
DECLARE seq VARCHAR(1);
DECLARE in_pit REAL;
DECLARE earned_runs REAL;
DECLARE accum_ip REAL;
DECLARE accum_er REAL;
DECLARE earned_run_avg REAL;
DECLARE prev_year YEAR(4);
DECLARE end_of_cursor BOOLEAN;
DECLARE c1 CURSOR FOR
SELECT Starting_Pitcher, Game_Date, Game_Number, innings_pitched, ER
FROM ip_ER_ERA_subtotal
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;
INSERT INTO ip_ER_ERA_subtotal
(Starting_Pitcher, Game_Date, Game_Number, innings_pitched, ER)
SELECT Starting_Pitcher, Game_Date, Game_Number, innings_pitched, ER
FROM starting_pitcher_game_log;
SET end_of_cursor := FALSE;
SET prev_year := 0;
OPEN c1;
fetch_loop: LOOP
FETCH c1 INTO pit_id, gdate, seq, in_pit, earned_runs;
IF end_of_cursor THEN
LEAVE fetch_loop;
END IF;
IF YEAR(gdate) != prev_year THEN
SET accum_ip := 0.0;
SET accum_er := 0.0;
SET earned_run_avg := 0.0;
SET prev_year := YEAR(gdate);
END IF;
SET accum_ip := accum_ip + in_pit;
SET accum_er := accum_er + ER;
SET earned_run_avg := (accum_er / accum_ip) * 9;
UPDATE ip_ER_ERA_subtotal
SET ip_total = accum_ip,
ER_total = accum_er,
STD_ERA = earned_run_avg
WHERE Starting_Pitcher = pit_id
AND ER = earned_runs
AND Game_Date = gdate
AND Game_Number = seq;
END LOOP;
CLOSE c1;
END
$$
I get the following error:
Unknown column 'ER' in 'field list'
Here is the screenshot of the table:
Now the "ER" column populated but no more "ip_total"
Ok, it finally worked with the below code. Not sure, but I had a hunch that it wasn't liking the name of the field "ER" from the table we were calling up the values (starting_pitcher_game_log) to be inserted into the new table. Don't know why it didn't like it...
EDIT: Here's my edited code to handle "NULL" and divide-by-zero situations:
DELIMITER $$
CREATE PROCEDURE accumulate_ip_ER_ERA()
BEGIN
DECLARE pit_id VARCHAR(8);
DECLARE gdate DATE;
DECLARE seq INT;
DECLARE in_pit REAL;
DECLARE ER_id REAL;
DECLARE accum_ip REAL;
DECLARE accum_er REAL;
DECLARE earned_run_avg REAL;
DECLARE prev_year YEAR(4);
DECLARE end_of_cursor BOOLEAN;
DECLARE c1 CURSOR FOR
SELECT Starting_Pitcher, Game_Date, Game_Number, innings_pitched, earned_runs
FROM ip_ER_ERA_subtotal
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;
INSERT INTO ip_ER_ERA_subtotal (Starting_Pitcher, Game_Date, Game_Number, innings_pitched, earned_runs)
SELECT Starting_Pitcher, Game_Date, Game_Number, innings_pitched, earned_runs,
IFNULL(innings_pitched, 0), -- replace NULL with 0, if
IFNULL(earned_runs, 0) -- column not initialized
FROM starting_pitcher_game_log;
END IF;
SET end_of_cursor := FALSE;
SET prev_year := 0;
OPEN c1;
fetch_loop: LOOP
FETCH c1 INTO pit_id, gdate, seq, in_pit, ER_id;
IF end_of_cursor THEN
LEAVE fetch_loop;
END IF;
IF YEAR(gdate) != prev_year THEN
SET accum_ip := 0.0;
SET accum_er := 0;
SET earned_run_avg := 0.0;
SET prev_year := YEAR(gdate);
END IF;
SET accum_ip := accum_ip + in_pit;
SET accum_er := accum_er + ER_id;
IF accum_er = 0 THEN -- prevent divide-by-zero
SET earned_run_avg := 0;
ELSE
SET earned_run_avg := (accum_er / accum_ip) * 9;
END IF;
UPDATE ip_ER_ERA_subtotal
SET ip_total = accum_ip,
ER_total = accum_er,
STD_ERA = earned_run_avg
WHERE Starting_Pitcher = pit_id
AND Game_Date = gdate
AND Game_Number = seq;
END LOOP;
CLOSE c1;
END
$$
error:
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 '(innings_pitched, 0), -- replace NULL with 0, if IFNULL(earned_runs, ' at line 25
UPDATE: Screenshots of table when sorting by STD_ERA showing abnormally high STD_ERA values at one end of the range for that field or grayed-out "NULL" values at the other end of the range.
Right; let's see what we have here.
First, the code has to be blocked as follows:
So your
DECLARE CURSOR c2
must appear betweenDECLARE CURSOR c1
andDECLARE CONTINUE HANDLER
. Also, you only need oneCONTINUE HANDLER
because it takes effect from the point of declaration to the end of the procedure.Next is the statement
The named columns in the
SELECT
clause are the columns you're selecting from, not the ones you're inserting into, so they have to be columns in the tablestarting_pitchers_game_log
. Also, since the columns not being copied fromstarting_pitchers_game_log
(that is,ip_total
,er_total
andera
) all have default values, you could use a column list on theINSERT
statement, like so:This saves typing, documents which columns you're actually inserting values into and insulates your
INSERT
statement from the physical order of columns in the source and target tables.Next, once you finish the
CURSOR c1
loop, don't truncate the table or you'll lose all the work you've just done!TRUNCATE TABLE
deletes all rows currently in the table, and is used here to clear out the results of the previous run.Finally, the two loops have to have different labels, say
fetch_loop_1
andfetch_loop_2
. You would also need to resetaccum
andend_of_cursor
before entering the second loop. However, in this case I believe we can do everything in one loop with one cursor, which makes the code simpler and thus easier to maintain.Here's the complete procedure:
That should do the job. If anyone finds a bug, by all means please point it out.
EDIT: I've just added some code to illustrate how to protect against nulls coming from the source table, and how to avoid a divide-by-zero on the ERA calculation.
EDIT: I've changed back to my original column and table names in order to reduce my own confusion.
EDIT: Code changed to be consistent with the answer to How can I add a column to a work table using a new stored procedure