如何在同一 table 中添加一个在另一列上递增的列?

How can I add a column that increments on another column in same table?

我有一个 table 和一个名为 "IP" 的列,我想在同一个 table "YTD_IP" 中创建另一个列,它会给出累计年份- 一年中任何给定比赛的 "IP"(投球局数)的最新总和反映了同一赛季之前的比赛(rows/events)中投球的局数总和。一旦年份发生变化,我希望总和再次从 0 开始。

这里是 "PIT_ID"、"YEAR_ID"、"IP" 列的数据样本,我希望看到 "YTD_IP" 列的数据:

Pit_ID  YEAR_ID  IP      YTD_IP
aased001      1977  9.0000    9
aased001      1977  9.0000    18
aased001      1977  7.0000    25
aased001      1977  5.0000    30
aased001      1977  6.3333    36.3333
aased001      1977  6.3333    42.6666
aased001      1977  7.0000    49.6666
aased001      1977  6.0000    55.6666
aased001      1977  9.0000    64.6666
aased001      1977  9.0000    73.6666
aased001      1977  5.0000    78.6666
aased001      1977  6.3333    84.9999
aased001      1977  7.3333    92.3333
aased001      1978  4.3333     4.3333
aased001      1978  7.0000    11.3333
aased001      1978  6.3333    17.6666
aased001      1978  3.3333    20.9999

我整理了以下代码:

ALTER TABLE starting_pitcher_game_log ADD COLUMN YTD_IP VARCHAR(255);
    SET YTD_IP:= 0;
    SELECT a.IP,  b.YEAR_ID
      IF(@prevYEAR_ID != YEAR_ID,IP,@YTD_IP+IP) AS IP,
      @prevYEAR_ID=YEAR_ID
    FROM starting_pitcher_game_log

但这是不对的,因为它得到以下错误:

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(@prevYEAR_ID != YEAR_ID,IP,@YTD_IP+IP) AS IP,
          @prevYEAR_ID=YEAR_ID
' at line 2

有没有办法确保它适应未来将玩的游戏?

任何帮助都会大有帮助。

screen shot of full table

嗨,达尔文,

您能否分享适用于临时调用列的代码以及适用于可创建累计和字段的永久列的代码?特别是,我想在 table 中创建另一个名为 "YTD_IP" 的列,它会给出从赛季开始以来 "IP"(投球局数)的累计年初至今总和直到那个赛季的任何给定比赛,反映给定投手在给定比赛之前的比赛(rows/events)中投出的局数+该场比赛中投出的局数的总和。一旦季节发生变化,我希望总和再次从 0 开始。

在此先感谢您的帮助。

我给你最好的建议是,不要这样做。存储可以从数据库中的其他信息导出的信息通常被认为是非常糟糕的设计,并且试图依赖数据库中行的顺序 肯定会发疯。

这是标准化您的 table 的第一步:

-- Table: teams

-- DROP TABLE teams;

CREATE TABLE teams
(
  team_id character(3) primary key,
  team_name varchar(255),
  team_city varchar(255)
) engine=innodb;

-- Table: starting_pitchers_game_log

-- DROP TABLE starting_pitchers_game_log;

CREATE TABLE starting_pitchers_game_log
(
  pitcher_id character(10) NOT NULL,
  game_date date NOT NULL,
  opposing_team character(3),
  game_seq integer NOT NULL,
  outcome character(1),
  innings_pitched real,
  bfp integer,
  hits integer,
  runs integer,
  errors integer,
  homeruns integer,
  bb integer,
  k integer,
  ibb integer,
  hbp integer,
  wp integer,
  balks integer,
  CONSTRAINT starting_pitcher_log_pk
      PRIMARY KEY (pitcher_id , game_date , game_seq ),
  CONSTRAINT team_fk FOREIGN KEY (opposing_team)
      REFERENCES teams (team_id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION
) engine=innodb;

(我不关注棒球,所以我只能猜测一些列名。)请注意,year_idmonth_idday_id 列已消失,正如我在评论中指出的那样,可以从 game_date 列重新创建这些值。您的 game_id 专栏也不见了;这可以通过连接 opposing_teamgame_dategame_seq 重新创建(我认为这是为了解释 double-headers 等)我还转换了 WL 到一个列中,用于保存值 "W"(获胜)、"L"(失败)和 "T"(平局)。

teams table 提供了一个查找 table 的 3 个字符的团队 ID。它可以扩展以保存您想要的任何其他团队数据。 (请注意,它是为了描述团队 本身; 团队 活动 将在另一个 table 中进行。)

为了回答您关于 "constraint" 子句的问题,第一个子句(CONSTRAINT starting_pitcher_log_pk 及其下方的缩进线)指定这三列的串联作为每个子句的主要唯一标识符table 中的行。第二个(CONSTRAINT team_fk FOREIGN KEY (opposing_team) 和它下面的缩进线)意味着要将值放在 opposing_team 列中,它 必须已经存在 teams.team_id列;你不能和一个不存在的球队比赛。

现在开始实际回答您的原始问题。我在 MySQL 上想出的最佳解决方案是一个 scratch table 和一个存储过程,如下所示:

-- Table: ip_subtotal

-- DROP TABLE ip_subtotal;

CREATE TABLE ip_subtotal
(
  pitcher_id char(10) NOT NULL,
  game_date date NOT NULL,
  game_seq int(11) NOT NULL,
  innings_pitched double,
  ip_total double DEFAULT '0.0',
  CONSTRAINT ip_subtotal_pk
      PRIMARY KEY (pitcher_id , game_date , game_seq )
) ENGINE=InnoDB;

和存储过程:

------------------------------------------------------------------------------    --
-- Routine DDL
-- Note: comments before and after the routine body will not be stored by the server
-- --------------------------------------------------------------------------------
DELIMITER $$

CREATE PROCEDURE accumulate_innings()
BEGIN
    DECLARE pit_id CHAR(10);
    DECLARE gdate DATE;
    DECLARE seq INT;
    DECLARE in_pit REAL;
    DECLARE accum REAL;
    DECLARE prev_year YEAR(4);
    DECLARE end_of_cursor BOOLEAN;

    DECLARE c1 CURSOR FOR
        SELECT pitcher_id, game_date, game_seq, innings_pitched
            FROM ip_subtotal
            ORDER BY pitcher_id, game_date, game_seq;

    DECLARE CONTINUE HANDLER FOR NOT FOUND
        SET end_of_cursor := TRUE;

    TRUNCATE TABLE ip_subtotal;
    INSERT INTO ip_subtotal
        SELECT pitcher_id, game_date, game_seq, 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_subtotal
            SET ip_total = accum
            WHERE pitcher_id = pit_id
              AND game_date = gdate
              AND game_seq = seq;
    END LOOP;
    CLOSE c1;
END

此程序清除 table ip_subtotal,从主 table 填充它,然后汇总投球局的 运行ning 总数。它还使用简单的 control-break 在年初重置累加器。通过执行 运行 程序后

CALL accumulate_innings();

您可以根据需要查询 ip_subtotal table 或将其加入 starting_pitchers_game_log table。

该程序还可以扩展以接受开始和结束日期;我把它留作 reader.

的练习

希望这对您有所帮助;这很有趣,迫使我学习了一点 MySQL。