sql >> Database >  >> RDS >> Mysql

Hoe kan ik een kolom toevoegen die op een andere kolom in dezelfde tabel wordt verhoogd?

Mijn beste advies aan jou is:doe dit niet. Het opslaan van informatie die kan worden afgeleid uit andere informatie in de database wordt over het algemeen als een zeer slecht ontwerp beschouwd en proberen te vertrouwen op de volgorde van de rijen in de database is een zeker pad naar waanzin.

Hier is een eerste poging om uw tafel te normaliseren:

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

(Ik volg honkbal niet, dus ik kon alleen maar raden naar enkele kolomnamen.) Merk op dat de year_id , month_id en day_id kolommen zijn verdwenen, omdat die waarden opnieuw kunnen worden gemaakt vanaf de game_date kolom zoals ik heb aangegeven in de opmerkingen. Ook je game_id kolom is verdwenen; dit kan opnieuw worden gemaakt door opposing_team aan elkaar te koppelen , game_date en game_seq (waarvan ik aanneem dat het rekening houdt met dubbele headers &c.) Ik heb ook W geconverteerd en L in een enkele kolom die bedoeld is om de waarden "W" (winst), "L" (verlies) en "T" (gelijkspel) te bevatten.

De teams tabel biedt een opzoektabel voor de team-ID's van 3 tekens. Het kan worden uitgebreid om andere teamgegevens op te slaan die u wilt. (Let op:het is bedoeld om het team zelf te beschrijven; team activiteiten zou in een andere tafel gaan.)

Om uw vraag over de "beperkingsclausules" te beantwoorden, de eerste (CONSTRAINT starting_pitcher_log_pk en de ingesprongen regel eronder) geeft aan dat de aaneenschakeling van die drie kolommen dient als de primaire unieke identificatie voor elke rij in de tabel. De tweede (CONSTRAINT team_fk FOREIGN KEY (opposing_team) en de ingesprongen regels eronder) betekent dat voor een waarde die moet worden geplaatst in het opposing_team kolom het moet al bestaan in de teams.team_id kolom; je kunt niet spelen tegen een team dat niet bestaat.

Nu werken aan het daadwerkelijk beantwoorden van uw oorspronkelijke vraag. De beste oplossing die ik kon bedenken op MySQL was een kladtabel en een opgeslagen procedure, als volgt:

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

En de opgeslagen procedure:

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

Deze procedure wist de tabel ip_subtotal , vult het in vanaf de hoofdtafel en rolt vervolgens het lopende totaal op voor de gegooide innings. Het gebruikt ook een eenvoudige bedieningsonderbreking om de accu aan het begin van het jaar te resetten. Nadat u de procedure heeft uitgevoerd door

. uit te voeren
CALL accumulate_innings();

u kunt de ip_subtotal . opvragen tafel of voeg het toe terug naar de starting_pitchers_game_log tafel naar wens.

De procedure zou ook kunnen worden uitgebreid om een ​​start- en einddatum te accepteren; Ik laat dat als een oefening voor de lezer.

Ik hoop dat dit helpt; het was interessant en dwong me om een ​​beetje MySQL te leren.




  1. MySQL-datumvergelijkingsfilter

  2. mysqli_stmt::num_rows() geeft de verkeerde waarde terug

  3. Hoe de mediaan te berekenen in MySQL

  4. Mysql-database maken met sequelize (nodejs)