Най-добрият ми съвет към вас е, не правете това. Съхраняването на информация, която може да бъде извлечена от друга информация в базата данни, обикновено се счита за много лош дизайн и опитът да се разчита на реда на редовете в базата данни е сигурен път към лудостта.
Ето един първи път за нормализиране на вашата таблица:
-- 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_id
, month_id
и day_id
колоните са изчезнали, тъй като тези стойности могат да бъдат пресъздадени от game_date
колона, както посочих в коментарите. Също така вашият game_id
колоната е изчезнала; това може да бъде пресъздадено от конкатениране на opposing_team
, game_date
и game_seq
(което предполагам, че отчита двойните заглавки и др.) Преобразувах също W
и L
в една колона, предназначена да съдържа стойностите „W“ (победа), „L“ (загуба) и „T“ (равенство).
teams
таблицата предоставя справочна таблица за 3-знаковите идентификатори на екипа. Може да се разшири, за да съдържа всякакви други данни за екипа, които искате. (Обърнете внимание, че има за цел да опише самия отбор; екипни дейности ще отиде на друга маса.)
За да отговорите на въпроса ви относно клаузите "ограничение", първата (CONSTRAINT starting_pitcher_log_pk
и ред с отстъп под него) указва, че конкатенацията на тези три колони служи като основен уникален идентификатор за всеки ред в таблицата. Вторият (CONSTRAINT team_fk FOREIGN KEY (opposing_team)
и редовете с отстъп под него) означава, че за дадена стойност трябва да бъде поставена в opposing_team
колона трябва вече да съществува в teams.team_id
колона; не можеш да играеш срещу отбор, който не съществува.
Сега да работим върху действителния отговор на първоначалния си въпрос. Най-доброто решение, което можех да измисля за MySQL, беше скреч таблица и съхранена процедура, както следва:
-- 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
Тази процедура изчиства таблицата ip_subtotal
, попълва го от основната маса, след което набира текущата сума за дадени ининги. Той също така използва просто прекъсване на контрола за нулиране на акумулатора в началото на годината. След като изпълните процедурата, като изпълните
CALL accumulate_innings();
можете да направите заявка за ip_subtotal
таблица или я присъединете обратно към starting_pitchers_game_log
таблица по желание.
Процедурата може също да бъде разширена, за да приеме начална и крайна дата; Оставям това като упражнение за читателя.
Надявам се това да помогне; беше интересно и ме принуди да науча малко MySQL.