Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Wie kann ich eine Spalte hinzufügen, die in einer anderen Spalte in derselben Tabelle erhöht wird?

Mein bester Rat an Sie ist, tun Sie dies nicht. Das Speichern von Informationen, die aus anderen Informationen in der Datenbank abgeleitet werden können, wird im Allgemeinen als sehr schlechtes Design angesehen und der Versuch, sich auf die Reihenfolge der Zeilen in der Datenbank zu verlassen ist ein sicherer Weg in den Wahnsinn.

Hier ist ein erster Versuch, Ihre Tabelle zu normalisieren:

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

(Ich verfolge Baseball nicht, daher konnte ich einige der Spaltennamen nur erraten.) Beachten Sie, dass die year_id , month_id und day_id Spalten sind weg, da diese Werte aus dem game_date neu erstellt werden können Spalte, wie ich in den Kommentaren angegeben habe. Auch Ihre game_id Spalte ist weg; Dies kann durch Verketten von opposing_team neu erstellt werden , game_date und game_seq (was ich vermute, um doppelte Header &c. zu berücksichtigen.) Ich habe auch W konvertiert und L in eine einzelne Spalte, die die Werte "W" (Gewinn), "L" (Verlust) und "T" (Unentschieden) aufnehmen soll.

Die teams table bietet eine Nachschlagetabelle für die 3-Zeichen-Team-IDs. Es kann erweitert werden, um beliebige andere Teamdaten zu speichern. (Beachten Sie, dass es das Team selbst; beschreiben soll Team Aktivitäten würde in eine andere Tabelle gehen.)

Um Ihre Frage zu den "constraint"-Klauseln zu beantworten, die erste (CONSTRAINT starting_pitcher_log_pk und die eingerückte Zeile darunter) gibt an, dass die Verkettung dieser drei Spalten als primäre eindeutige Kennung für jede Zeile in der Tabelle dient. Der zweite (CONSTRAINT team_fk FOREIGN KEY (opposing_team) und die eingerückten Zeilen darunter) bedeutet, dass ein Wert in opposing_team platziert werden muss Spalte muss bereits existieren in teams.team_id Säule; Du kannst nicht gegen ein Team spielen, das nicht existiert.

Jetzt arbeiten Sie daran, Ihre ursprüngliche Frage tatsächlich zu beantworten. Die beste Lösung, die ich für MySQL finden konnte, war eine Scratch-Tabelle und eine gespeicherte Prozedur wie folgt:

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

Und die gespeicherte Prozedur:

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

Diese Prozedur löscht die Tabelle ip_subtotal , füllt es aus der Haupttabelle und rollt dann die laufende Summe für die gepitchten Innings auf. Es verwendet auch eine einfache Steuerunterbrechung, um den Akkumulator zu Beginn des Jahres zurückzusetzen. Nachdem Sie die Prozedur ausgeführt haben, indem Sie

CALL accumulate_innings();

Sie können die ip_subtotal abfragen Tabelle oder füge es wieder dem starting_pitchers_game_log hinzu Tabelle wie gewünscht.

Das Verfahren könnte auch erweitert werden, um ein Start- und Enddatum zu akzeptieren; Ich überlasse das dem Leser als Übung.

Hoffe das hilft; es war interessant und zwang mich, ein wenig MySQL zu lernen.