Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Como posso adicionar uma coluna que aumenta em outra coluna na mesma tabela?


Meu melhor conselho para você é:não faça isso. Armazenar informações que podem ser derivadas de outras informações no banco de dados geralmente é considerado um design muito ruim e tentar confiar na ordem das linhas no banco de dados é um caminho seguro para a loucura.

Aqui está um primeiro passo para normalizar sua tabela:
-- 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;

(Eu não sigo beisebol, então eu só poderia adivinhar alguns dos nomes das colunas.) Observe que o year_id , month_id e day_id colunas desapareceram, pois esses valores podem ser recriados a partir do game_date coluna como indiquei nos comentários. Também seu game_id coluna se foi; isso pode ser recriado a partir da concatenação de opposing_team , game_date e game_seq (que eu presumo é para levar em conta cabeçalhos duplos etc.) Eu também converti W e L em uma única coluna destinada a conter os valores "W" (vitória), "L" (perda) e "T" (empate).

As teams table fornece uma tabela de pesquisa para os IDs de equipe de 3 caracteres. Ele pode ser expandido para armazenar quaisquer outros dados de equipe que você desejar. (Observe que se destina a descrever a equipe própria; equipe atividades iria para outra mesa.)

Para responder à sua pergunta sobre as cláusulas de "restrição", a primeira (CONSTRAINT starting_pitcher_log_pk e a linha recuada abaixo dela) especifica que a concatenação dessas três colunas serve como o identificador exclusivo primário para cada linha na tabela. O segundo (CONSTRAINT team_fk FOREIGN KEY (opposing_team) e as linhas recuadas abaixo) significa que para um valor ser colocado no opposing_team coluna que já deve existir no teams.team_id coluna; você não pode jogar contra um time que não existe.

Agora, trabalhe para realmente responder à sua pergunta original. A melhor solução que encontrei no MySQL foi uma tabela de rascunho e um procedimento armazenado, como segue:
-- 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;

E o procedimento armazenado:
------------------------------------------------------------------------------    --
-- 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

Este procedimento limpa a tabela ip_subtotal , preenche-o a partir da tabela principal e, em seguida, acumula o total acumulado das entradas lançadas. Ele também usa uma simples interrupção de controle para redefinir o acumulador no início do ano. Depois de executar o procedimento executando
CALL accumulate_innings();

você pode consultar o ip_subtotal tabela ou junte-a de volta ao starting_pitchers_game_log mesa conforme desejado.

O procedimento também pode ser estendido para aceitar uma data de início e término; Deixo como exercício para o leitor.

Espero que isto ajude; foi interessante e me obrigou a aprender um pouco sobre MySQL.