Mysql
 sql >> Base de données >  >> RDS >> Mysql

Comment puis-je ajouter une colonne qui s'incrémente sur une autre colonne dans la même table ?

Mon meilleur conseil pour vous est, ne faites pas ça. Le stockage d'informations qui peuvent être dérivées d'autres informations dans la base de données est généralement considéré comme une très mauvaise conception et tente de s'appuyer sur l'ordre des lignes dans la base de données est un chemin sûr vers la folie.

Voici une première étape de normalisation de votre table :

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

(Je ne suis pas le baseball, donc je ne pouvais que deviner certains des noms de colonne.) Notez que le year_id , month_id et day_id les colonnes ont disparu, car ces valeurs peuvent être recréées à partir de game_date colonne comme je l'ai indiqué dans les commentaires. Aussi votre game_id la colonne a disparu ; cela peut être recréé à partir de la concaténation de opposing_team , game_date et game_seq (ce qui, je suppose, tient compte des doubles en-têtes, etc.) J'ai également converti W et L dans une seule colonne destinée à contenir les valeurs "W" (victoire), "L" (défaite) et "T" (égalité).

Les teams table fournit une table de recherche pour les identifiants d'équipe à 3 caractères. Il peut être étendu pour contenir toutes les autres données d'équipe que vous souhaitez. (Notez qu'il est destiné à décrire l'équipe elle-même ; activités de l'équipe irait dans un autre tableau.)

Pour répondre à votre question sur les clauses "contraintes", la première (CONSTRAINT starting_pitcher_log_pk et la ligne en retrait en dessous) spécifie que la concaténation de ces trois colonnes sert d'identifiant unique principal pour chaque ligne du tableau. La seconde (CONSTRAINT team_fk FOREIGN KEY (opposing_team) et les lignes en retrait en dessous) signifie que pour qu'une valeur soit placée dans le opposing_team la colonne doit déjà exister dans le teams.team_id colonne; vous ne pouvez pas jouer contre une équipe qui n'existe pas.

Maintenant, pour travailler sur la réponse à votre question initiale. La meilleure solution que j'ai pu trouver sur MySQL était une table de travail et une procédure stockée, comme suit :

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

Et la procédure stockée :

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

Cette procédure efface la table ip_subtotal , le remplit à partir du tableau principal, puis cumule le total cumulé des manches lancées. Il utilise également une simple coupure de contrôle pour réinitialiser l'accumulateur au début de l'année. Après avoir exécuté la procédure en exécutant

CALL accumulate_innings();

vous pouvez interroger le ip_subtotal table ou joignez-la au starting_pitchers_game_log tableau comme vous le souhaitez.

La procédure pourrait également être étendue pour accepter une date de début et de fin; Je laisse cela comme un exercice pour le lecteur.

J'espère que cela t'aides; c'était intéressant et m'a obligé à apprendre un peu MySQL.