sql >> Database teknologi >  >> RDS >> Mysql

Hvordan kan jeg tilføje en kolonne til en arbejdstabel ved hjælp af en ny lagret procedure

Dette spørgsmål og dets svar bygger på svarene på Hvordan kan jeg kombinere to procedurer i én for at udfylde én tabel i stedet for at hver af de to procedurer udfylder sin egen tabel? og Hvordan kan jeg tilføje en kolonne, der stiger på en anden kolonne i samme tabel? , og svaret på dette spørgsmål nødvendiggør mindre ændringer af svaret på de to foregående, som jeg vil bemærke, når det er relevant.

Da beregningerne af "kandens hvileperiode" og "gennemsnitlige løb" er uafhængige af hinanden, anbefaler jeg en separat procedure for hver. Men da resultaterne af de to procedurer ofte vil blive brugt sammen, anbefaler jeg en fælles skrabetabel til beregningerne og foreslår refaktorering oprettelsen og populationen af ​​denne skrabetabell til en tredje procedure:

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 tidligere version brugte en normal, vedvarende tabel, fordi jeg endnu ikke var bekendt med MySQL's håndtering af midlertidige tabeller. En midlertidig tabel slettes automatisk, når brugeren logger af, og genvinder den plads, der bruges til afledte data, som kan genskabes efter behov. At slippe og genskabe tabellen svarer til TRUNCATE ing (bortset fra at tabellen ikke behøver at eksistere på forhånd), hvilket igen er meget hurtigere end en ubetinget DELETE , ifølge MySQL-dokumenterne. Jeg har foretaget passende annoterede ændringer til optjent-runs-gennemsnitlig procedure også.

Proceduren til at beregne pitchers hviletid følger igen standard "kontrol-break" formsprog. Bemærk, at vi læser den første post og opsætter kontrolfelterne én gang, før vi går ind i loopet, derefter tester vi inden for loopet for vores udgangstilstand, behandler den "aktuelle" post, læser den "næste" post og looper.

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 ;

I brug, pitcher_stats_reset() kaldes først for at initialisere arbejdstabellen. Når det er gjort, pitcher_stats_era() og pitcher_stats_rest_time() kan kaldes gentagne gange i vilkårlig rækkefølge. Hvis pitcher_stats_reset() ikke kaldes først, vil de to andre procedurer give en høflig påmindelse om at gøre det.




  1. Hvorfor returnerer denne simple MySQL-forespørgsel ikke rækken?

  2. Fjern kommaer ved hjælp af php fra mysql

  3. MySQL versus PDO

  4. Hvordan bruger man $db fra en anden .php til en anden .phps klasse ved hjælp af OOP?