sql >> Databasteknik >  >> RDS >> Mysql

Hur kan jag lägga till en kolumn som ökar på en annan kolumn i samma tabell?

Mitt bästa råd till dig är, gör inte det här. Att lagra information som kan härledas från annan information i databasen anses i allmänhet vara mycket dålig design, och försök att förlita sig på ordningen på raderna i databasen är en säker väg till galenskap.

Här är ett första pass för att normalisera ditt bord:

-- 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;

(Jag följer inte baseball, så jag kunde bara gissa på några av kolumnnamnen.) Observera att year_id , month_id och day_id kolumner är borta, eftersom dessa värden kan återskapas från game_date kolumn som jag angav i kommentarerna. Även ditt game_id kolumnen är borta; detta kan återskapas genom att sammanfoga opposing_team , game_date och game_seq (vilket jag antar är att ta hänsyn till dubbla rubriker etc.) Jag har också konverterat W och L i en enda kolumn avsedd att innehålla värdena "W" (vinst), "L" (förlust) och "T" (oavgjort).

teams Tabellen tillhandahåller en uppslagstabell för 3-char team-ID. Den kan utökas för att hålla andra lagdata du vill ha. (Observera att det är tänkt att beskriva laget självt; team aktiviteter skulle gå i en annan tabell.)

För att svara på din fråga om "begränsnings"-satserna, den första (CONSTRAINT starting_pitcher_log_pk och den indragna raden under den) anger att sammanlänkningen av dessa tre kolumner fungerar som den primära unika identifieraren för varje rad i tabellen. Den andra (CONSTRAINT team_fk FOREIGN KEY (opposing_team) och de indragna linjerna nedanför) betyder att ett värde ska placeras i opposing_team kolumnen den måste redan finnas i teams.team_id kolumn; du kan inte spela mot ett lag som inte finns.

Nu ska vi jobba på att faktiskt svara på din ursprungliga fråga. Den bästa lösningen jag kunde komma på på MySQL var en skraptabell och en lagrad procedur, enligt följande:

-- 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;

Och den lagrade proceduren:

------------------------------------------------------------------------------    --
-- 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

Denna procedur rensar tabellen ip_subtotal , fyller den från huvudtabellen och rullar sedan upp den löpande summan för innings. Den använder också en enkel kontrollpaus för att återställa ackumulatorn i början av året. När du har kört proceduren genom att köra

CALL accumulate_innings();

du kan fråga ip_subtotal bord eller gå med i starting_pitchers_game_log tabell enligt önskemål.

Förfarandet skulle också kunna utvidgas till att acceptera ett start- och slutdatum. Jag lämnar det som en övning för läsaren.

Hoppas det här hjälper; det var intressant och tvingade mig att lära mig lite MySQL.




  1. Konvertera MySQL-schema till Github Wiki?

  2. Hitta liknande talmönster i tabellen

  3. MySQL Group By med topp N-nummer av varje slag

  4. Mysql-anslut till server:Åtkomst nekad för användare [e-postskyddad]