sql >> Databasteknik >  >> RDS >> Mysql

Hur kan jag lägga till en kolumn i en arbetstabell med en ny lagrad procedur

Den här frågan och dess svar bygger på svaren på Hur kan jag kombinera två procedurer i en för att fylla en tabell i stället för att var och en av de två procedurerna fyller sin egen tabell? och Hur kan jag lägga till en kolumn som ökar på en annan kolumn i samma tabell? , och svaret på denna fråga kräver mindre ändringar av svaret på de två föregående, vilket jag ska notera när det är lämpligt.

Eftersom beräkningarna "kanna viloperiod" och "intjänade körningar genomsnitt" är oberoende av varandra, rekommenderar jag en separat procedur för var och en. Men eftersom resultaten av de två procedurerna ofta kommer att användas tillsammans rekommenderar jag en gemensam skraptabell för beräkningarna och föreslår refaktorering skapandet och populationen av den skraplotten till en tredje procedur:

DELIMITER $$

-- DROP PROCEDURE pitcher_stats_reset $$

CREATE PROCEDURE pitcher_stats_reset()
BEGIN
  DROP TEMPORARY TABLE IF EXISTS pitcher_stats_temp;

  CREATE TEMPORARY TABLE pitcher_stats_temp
  (
    pitcher_id      char(10)    NOT NULL,
    game_date       date        NOT NULL,
    game_seq        int         NOT NULL,
    innings_pitched double      DEFAULT 0.0,
    ip_total        double      DEFAULT 0.0,
    earned_runs     INT         DEFAULT 0,
    er_total        INT         DEFAULT 0,
    std_era         DOUBLE      DEFAULT 0.0,
    starter_rest    INT         DEFAULT 0,
    CONSTRAINT pitcher_stats_temp_pk
      PRIMARY KEY (pitcher_id , game_date , game_seq )
  ) ENGINE=InnoDB;

  INSERT INTO pitcher_stats_temp
        (pitcher_id, game_date, game_seq, innings_pitched, earned_runs)
      SELECT pitcher_id, game_date, game_seq,
          IFNULL(innings_pitched, 0),  -- replace NULL with 0, if
          IFNULL(runs, 0)              --   column not initialized
        FROM starting_pitchers_game_log;
END $$

DELIMITER ;

Den tidigare versionen använde en normal, beständig tabell eftersom jag ännu inte var bekant med MySQL:s hantering av temporära tabeller. En temporär tabell släpps automatiskt när användaren loggar ut, vilket tar tillbaka utrymmet som används för härledd data som kan återskapas vid behov. Att släppa och återskapa tabellen motsvarar TRUNCATE ning (förutom att tabellen inte behöver existera i förväg) vilket i sin tur är mycket snabbare än en ovillkorlig DELETE , enligt MySQL-dokumenten. Jag har gjort lämpliga annoterade ändringar i earned-runs-average procedure likaså.

Proceduren för att beräkna kannors vilotid följer återigen standarden "kontroll-brytning" idiom. Observera att vi läser den första posten och ställer in kontrollfälten en gång innan vi går in i slingan, sedan inom slingan testar vi för vårt utgångsförhållande, bearbetar den "nuvarande" posten, läser "nästa" posten och loopar.

DROP PROCEDURE IF EXISTS pitcher_stats_rest_time;

DELIMITER $$

CREATE PROCEDURE pitcher_stats_rest_time()
  BEGIN
    DECLARE pit_id          CHAR(10);
    DECLARE prev_pit        CHAR(10);
    DECLARE gdate           DATE;
    DECLARE seq             INT;
    DECLARE prev_date       DATE;
    DECLARE rest_days       INT;
    DECLARE end_of_cursor   BOOLEAN;

    DECLARE no_table CONDITION FOR SQLSTATE '42S02';

    DECLARE c1 CURSOR FOR
      SELECT pitcher_id, game_date, game_seq
        FROM pitcher_stats_temp
        ORDER BY pitcher_id, game_date, game_seq;

    DECLARE CONTINUE HANDLER FOR NOT FOUND
      SET end_of_cursor := TRUE;

    DECLARE EXIT HANDLER FOR no_table
    BEGIN
      SIGNAL no_table
        SET MESSAGE_TEXT = "Work table not initialized. Please call pitcher_stats_reset() before continuing",
        MYSQL_ERRNO = 1146;
    END;

    SET end_of_cursor := FALSE;

    -- Read first record and initialize control fields
    OPEN c1;
    FETCH c1 INTO pit_id, gdate, seq;
    SET prev_date := 0;
    SET prev_pit := pit_id;

    fetch_loop: LOOP
      -- Test for end-of-cursor
      IF end_of_cursor THEN
        LEAVE fetch_loop;
      END IF;

      -- Test for change in control fields. If the pitcher changes,
      --  fake a change in the year to trigger the break.
      IF pit_id != prev_pit THEN
        SET prev_date := 0;
      END IF;

      IF YEAR(prev_date) = YEAR(gdate) THEN
        SET rest_days := DATEDIFF(gdate, prev_date);
      ELSE
        SET rest_days := 0;
      END IF;

      UPDATE pitcher_stats_temp
        SET starter_rest = rest_days
        WHERE pitcher_id = pit_id
          AND game_date = gdate
          AND game_seq = seq;

      -- After processing record, update control fields
      SET prev_date := gdate;
      SET prev_pit := pit_id;

      -- Read next record and repeat
      FETCH c1 INTO pit_id, gdate, seq;
    END LOOP;

    CLOSE c1;

  END $$

DELIMITER ;

Vid användning, pitcher_stats_reset() anropas först, för att initiera arbetstabellen. När det är gjort, pitcher_stats_era() och pitcher_stats_rest_time() kan kallas upprepade gånger i valfri ordning. Om pitcher_stats_reset() inte anropas först, kommer de andra två procedurerna att utfärda en artig påminnelse om att göra det.




  1. Mysql Kolumn begränsning som inte tom / krävs

  2. Visa en tabell FULLTEXT indexerade kolumner

  3. Jämför Facebooks utbud av vänlista med MySQL-tabellen

  4. Ta bort dubblettrader från tabell i Oracle