我怎样才能将两个过程合二为一来填充一个 table 而不是两个过程中的每一个都填充它自己的 table?

How can I combine two procedures in one to populate one table rather than each of the two procedures populating it's own table?

我用 Sequel Pro 创建了两个 table,每个都在 MySQL 中填充了不同的程序。虽然每个 table 在 运行 各自的程序之后都有正确的信息,但我认为如果我合并一些 table 我的数据将不那么分散 tables ] 更多。

所以,我想做的是将来自两个 table 的数据合并为一个。下面是我用来尝试完成此操作的代码。不幸的是,它没有用,我们将不胜感激任何对代码的帮助。

创建table代码:

-- 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

程序代码:

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

我收到以下错误:

 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

这是第一个的截图 table 我已经创建了 "ip_subtotal"

这是第二个的截图table我已经创建了"ER_subtotal"

更新:

这基本上是你的相同代码,我对它做了一些小改动:

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

这是错误:

Incorrect number of FETCH variables

我确实尝试查看是否未获取任何变量并尝试添加 "accum_ip"、"accum_er"、"earned_run_avg" 但它没有用...它似乎这八个变量就是你的 fetch 语句中的后三个 + 那些应该是需要的......

这是 table 代码:

-- 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

更新:

这是基于您的更改的代码,但 ER、ER_total 和 STD_ERA 列仅填充了 "Null" 个值。

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
  $$

这是 table 的屏幕截图:

难道在任何给定的游标操作中只能处理一个公式?

SET accum_ip := accum_ip + in_pit;
  SET accum_er := accum_er + ER;
  SET earned_run_avg := (accum_er / accum_ip) * 9

感谢您的帮助。

达尔文, 好的,这是用正确的值填充以下列的编辑代码:Starting_Pitcher、Game_Date、Game_Number、table ip_ER_ERA_subtotal 的局数和 ER . ER_total 和 STD_ERA 列全为“0”。
这是代码:

    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
$$

我收到以下错误:

Unknown column 'ER' in 'field list'

这里是table的截图:

现在填充了 "ER" 列,但不再填充 "ip_total"

好的,它终于可以使用下面的代码了。不确定,但我有一种预感,它不喜欢 table 中的字段名称 "ER" 我们正在调用要插入到新字段中的值 (starting_pitcher_game_log) table。不知道为什么不喜欢...

编辑:这是我编辑的代码,用于处理 "NULL" 和被零除的情况:

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

      $$

错误:

您的 SQL 语法有误;检查与您的 MySQL 服务器版本相对应的手册,以了解在 '(innings_pitched, 0) 附近使用的正确语法,-- 将 NULL 替换为 0,如果 IFNULL(earned_runs, ' 在第 25 行

更新: 按 STD_ERA 排序时 table 的屏幕截图显示该字段范围一端异常高的 STD_ERA 值或范围另一端的灰色 "NULL" 值.

对;让我们看看这里有什么。

首先要屏蔽的代码如下:

variable declarations
cursor declarations
handler declarations
everything else

所以你的DECLARE CURSOR c2必须出现在DECLARE CURSOR c1DECLARE CONTINUE HANDLER之间。另外,你只需要一个CONTINUE HANDLER,因为它从声明点到程序结束都有效。

接下来是声明

INSERT INTO ip_ER_subtotal
    SELECT Starting_Pitcher, Game_Date, Game_Number, innings_pitched, 0.0
        FROM starting_pitchers_game_log;

SELECT 子句中的命名列是您从中选择的列,不是您选择的列重新 插入 ,因此它们必须是 table starting_pitchers_game_log 中的列。此外,由于未从 starting_pitchers_game_log(即 ip_totaler_totalera)复制的列都具有默认值,因此您可以在 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 语句与源和目标 table 中列的物理顺序隔离。

接下来,一旦你完成了 CURSOR c1 循环,不要运行对 table 进行分类,否则你将失去所有你刚刚完成的工作! TRUNCATE TABLE删除当前table中的所有行,这里用来清除掉前面运行的结果。

最后,两个循环必须有不同的标签,比如说fetch_loop_1fetch_loop_2。在进入第二个循环之前,您还需要重置 accumend_of_cursor。然而,在这种情况下,我相信我们可以用一个游标在一个循环中完成所有事情,这使得代码更简单,因此更容易维护。

完整的程序如下:

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 ;

这应该可以完成工作。如果有人发现错误,请务必指出。

编辑:我刚刚添加了一些代码来说明如何防止来自源的空值table,以及如何避免在 ERA 计算中被零除。

编辑:为了减少我自己的困惑,我已经改回原来的专栏和 table 名称。

编辑:代码更改为与

的答案一致