Moje nejlepší rada pro vás je, nedělejte to. Ukládání informací, které lze odvodit z jiných informací v databázi, je obecně považováno za velmi špatný návrh a pokus spoléhat se na pořadí řádků v databázi je jistá cesta k šílenství.
Zde je první průchod normalizací vaší tabulky:
-- 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;
(Nesleduji baseball, takže jsem mohl jen odhadovat názvy některých sloupců.) Všimněte si, že year_id
, month_id
a day_id
sloupce jsou pryč, protože tyto hodnoty lze znovu vytvořit z game_date
sloupec, jak jsem uvedl v komentářích. Také vaše game_id
sloupec je pryč; toto lze znovu vytvořit zřetězením opposing_team
, game_date
a game_seq
(předpokládám, že to zohledňuje dvojitá záhlaví atd.) Také jsem převedl W
a L
do jednoho sloupce, který má obsahovat hodnoty „W“ (výhra), „L“ (prohra) a „T“ (remíza).
teams
tabulka poskytuje vyhledávací tabulku pro 3znaková ID týmu. Lze jej rozšířit tak, aby obsahoval jakákoli další týmová data, která chcete. (Všimněte si, že to má popisovat tým samotný; týmové činnosti by šlo do jiné tabulky.)
Abychom odpověděli na vaši otázku týkající se „omezení“ klauzulí, první z nich (CONSTRAINT starting_pitcher_log_pk
a odsazený řádek pod ním) určuje, že zřetězení těchto tří sloupců slouží jako primární jedinečný identifikátor pro každý řádek v tabulce. Druhý (CONSTRAINT team_fk FOREIGN KEY (opposing_team)
a odsazené řádky pod tím) znamenají, že pro hodnotu, která má být umístěna do opposing_team
sloupec, který musí již existovat v teams.team_id
sloupec; nemůžete hrát proti týmu, který neexistuje.
Nyní pracujte na skutečné odpovědi na vaši původní otázku. Nejlepším řešením, které jsem mohl na MySQL vymyslet, byla stírací tabulka a uložená procedura:
-- 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;
A uložená procedura:
------------------------------------------------------------------------------ --
-- 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
Tento postup vymaže tabulku ip_subtotal
, naplní jej z hlavního stolu a poté vygeneruje průběžný součet pro nahozené směny. K resetování akumulátoru na začátku roku také využívá jednoduchou ovládací přestávku. Po spuštění procedury spuštěním
CALL accumulate_innings();
můžete zadat dotaz na ip_subtotal
stůl nebo jej připojte zpět k starting_pitchers_game_log
podle potřeby.
Postup by mohl být také rozšířen tak, aby akceptoval počáteční a koncové datum; Nechám to jako cvičení pro čtenáře.
Snad to pomůže; bylo to zajímavé a donutilo mě to naučit se trochu MySQL.