sql >> Database >  >> RDS >> Mysql

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?

Rechts; laten we eens kijken wat we hier hebben.

Eerst moet de code als volgt worden geblokkeerd:

variable declarations
cursor declarations
handler declarations
everything else

Dus uw DECLARE CURSOR c2 moet verschijnen tussen DECLARE CURSOR c1 en DECLARE CONTINUE HANDLER . Je hebt ook maar één CONTINUE HANDLER . nodig omdat het van kracht wordt vanaf het moment van aangifte tot het einde van de procedure.

Het volgende is de verklaring

INSERT INTO ip_ER_subtotal
    SELECT Starting_Pitcher, Game_Date, Game_Number, innings_pitched, 0.0
        FROM starting_pitchers_game_log;

De benoemde kolommen in de SELECT clausule zijn de kolommen waaruit u selecteert, niet degene die u invoegt, dus het moeten kolommen zijn in de tabel starting_pitchers_game_log . Omdat de kolommen niet worden gekopieerd uit starting_pitchers_game_log (dat wil zeggen, ip_total , er_total en era ) hebben allemaal standaardwaarden, u kunt een kolomlijst gebruiken op de INSERT verklaring, zoals zo:

INSERT INTO pitcher_stats_temp
    (Starting_Pitcher, Game_Date, Game_Number, innings_pitched, er)
  SELECT pitcher_id, game_date, game_seq, innings_pitched, runs
    FROM starting_pitchers_game_log;

Dit bespaart typen, documenteert in welke kolommen u daadwerkelijk waarden invoegt en isoleert uw INSERT verklaring van de fysieke volgorde van kolommen in de bron- en doeltabellen.

Vervolgens, als u klaar bent met de CURSOR c1 loop, kort de tabel niet af of je verliest al het werk dat je net hebt gedaan! TRUNCATE TABLE verwijdert alle rijen die momenteel in de tabel staan ​​en wordt hier gebruikt om de resultaten van de vorige run te wissen.

Ten slotte moeten de twee lussen verschillende labels hebben, zeg fetch_loop_1 en fetch_loop_2 . U moet ook accum . resetten en end_of_cursor voordat u de tweede lus ingaat. In dit geval geloof ik echter dat we alles in één lus kunnen doen met één cursor, wat de code eenvoudiger en dus gemakkelijker te onderhouden maakt.

Hier is de volledige procedure:

DROP PROCEDURE IF EXISTS pitcher_stats_era;

DELIMITER $$

CREATE PROCEDURE pitcher_stats_era()
  BEGIN
    DECLARE pit_id CHAR(10);
    DECLARE gdate DATE;
    DECLARE seq INT;
    DECLARE in_pit REAL;
    DECLARE er INT;
    DECLARE accum_ip REAL;
    DECLARE accum_er INT;
    DECLARE earned_run_avg REAL;
    DECLARE prev_year YEAR(4);
    DECLARE end_of_cursor BOOLEAN;

    DECLARE no_table CONDITION FOR SQLSTATE '42S02';

    DECLARE c1 CURSOR FOR
      SELECT pitcher_id, game_date, game_seq, innings_pitched, earned_runs
        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;
------------------------------------------------------------------
-- The following steps are now performed by pitcher_stats_reset()
------------------------------------------------------------------
--  TRUNCATE TABLE ip_subtotal;  -- Clear our work table for a new run
    -- Copy data from main table into work table
--  INSERT INTO ip_subtotal
--      (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;
---------------------------------------------------------------------

    SET end_of_cursor := FALSE;  -- reset
    SET prev_year := 0;          -- reset control-break

    OPEN c1;

    fetch_loop: LOOP
      FETCH c1 INTO pit_id, gdate, seq, in_pit, er;
      IF end_of_cursor THEN
        LEAVE fetch_loop;
      END IF;

      -- check control-break conditions
      IF YEAR(gdate) != prev_year THEN
        SET accum_ip := 0.0;
        SET accum_er := 0;
        SET prev_year := YEAR(gdate);
      END IF;

      SET accum_ip := accum_ip + in_pit;
      SET accum_er := accum_er + er;
      IF accum_er = 0 THEN  -- prevent divide-by-zero
        SET earned_run_avg := 0;
      ELSE
        SET earned_run_avg := (accum_ip / accum_er) * 9;
      END IF;

      UPDATE pitcher_stats_temp
        SET ip_total = accum_ip,
            er_total = accum_er,
            std_era = earned_run_avg
        WHERE pitcher_id = pit_id
          AND game_date = gdate
          AND game_seq = seq;

    END LOOP;

    CLOSE c1;
  END
$$
DELIMITER ;

Dat zou het werk moeten doen. Als iemand een bug vindt, wijs hem dan vooral.

EDIT:ik heb zojuist wat code toegevoegd om te illustreren hoe te beschermen tegen nulls afkomstig van de brontabel en hoe een deel door nul op de ERA-berekening te voorkomen.

EDIT:ik heb mijn oorspronkelijke kolom- en tabelnamen teruggezet om mijn eigen verwarring te verminderen.

EDIT:Code gewijzigd om consistent te zijn met het antwoord op Hoe kan ik een kolom toevoegen aan een werktabel met behulp van een nieuwe opgeslagen procedure




  1. MySQL-verbinding op afstand mislukt met onbekende authenticatiemethode

  2. Krijg toegang tot de mening van experts over de MVP-top van 2020

  3. Voeg een inner join toe aan de mySQL GROUP_CONCAT-instructie

  4. Fatale fout:oproep naar niet-gedefinieerde functie sqlsrv_connect() in C:\xampp\htdocs