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.