sql >> Database >  >> RDS >> Mysql

Hoe kan ik een kolom aan een werktabel toevoegen met behulp van een nieuwe opgeslagen procedure?

Deze vraag, en het antwoord daarop, bouwen voort op de antwoorden op Hoe kan ik twee procedures in één combineren om één tabel te vullen in plaats van dat elk van de twee procedures zijn eigen tabel vult? en Hoe kan ik een kolom toevoegen die op een andere kolom in dezelfde tabel wordt verhoogd? , en het antwoord op deze vraag vereist kleine wijzigingen in het antwoord op de vorige twee, die ik indien nodig zal noteren.

Aangezien de berekeningen "pitcher rustperiode" en "gemiddelde verdiende runs" onafhankelijk van elkaar zijn, raad ik een aparte procedure aan voor elk. Omdat de resultaten van de twee procedures echter vaak samen worden gebruikt, raad ik een algemene rekentabel aan voor de berekeningen en stel refactoring de creatie en populatie van die krastafel in een derde 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 ;

De vorige versie gebruikte een normale, persistente tabel omdat ik nog niet bekend was met MySQL's behandeling van tijdelijke tabellen. Een tijdelijke tabel wordt automatisch verwijderd wanneer de gebruiker zich afmeldt, waardoor de ruimte wordt vrijgemaakt die wordt gebruikt voor afgeleide gegevens die indien nodig opnieuw kunnen worden gegenereerd. Het laten vallen en opnieuw maken van de tabel is gelijk aan TRUNCATE ing (behalve dat de tabel vooraf niet hoeft te bestaan), wat op zijn beurt veel sneller is dan een onvoorwaardelijke DELETE , volgens de MySQL-documenten. Ik heb de juiste geannoteerde wijzigingen aangebracht in de earned-runs-average procedure ook.

De procedure om de rusttijd van werpers te berekenen volgt opnieuw het standaard "control-break"-idioom. Merk op dat we het eerste record lezen en de controlevelden eenmaal instellen voordat we de lus binnengaan, dan testen we binnen de lus op onze uitgangsconditie, verwerken het "huidige" record, lezen het "volgende" record en lus.

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 ;

In gebruik, pitcher_stats_reset() wordt eerst aangeroepen om de werktabel te initialiseren. Zodra dat is gebeurd, pitcher_stats_era() en pitcher_stats_rest_time() kan herhaaldelijk in willekeurige volgorde worden opgeroepen. If pitcher_stats_reset() niet als eerste wordt gebeld, zullen de andere twee procedures een beleefde herinnering sturen om dit te doen.




  1. Hoe log/traceer ik Oracle opgeslagen procedure-aanroepen met parameterwaarden?

  2. mysql-replicatie - slave-server op één database

  3. Migratie schrijven om de primaire sleutel van het model te wijzigen met ManyToManyField

  4. SQL Server 2008 Spatial:vind een punt in polygoon