sql >> Databáze >  >> RDS >> Mysql

Jak mohu zkombinovat dvě procedury do jedné, aby se naplnila jedna tabulka, místo aby každá ze dvou procedur vyplňovala svou vlastní tabulku?

Že jo; podívejme se, co tu máme.

Nejprve je třeba kód zablokovat následovně:

variable declarations
cursor declarations
handler declarations
everything else

Takže váš DECLARE CURSOR c2 musí se objeví mezi DECLARE CURSOR c1 a DECLARE CONTINUE HANDLER . Potřebujete také pouze jeden CONTINUE HANDLER protože nabývá účinnosti od okamžiku deklarace do konce procedury.

Další je prohlášení

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

Pojmenované sloupce v SELECT klauzule jsou sloupce, ze kterých vybíráte ne ty, do kterých vkládáte, takže to musí být sloupce v tabulce starting_pitchers_game_log . Také proto, že sloupce nejsou zkopírovány z starting_pitchers_game_log (tj. ip_total , er_total a era ) všechny mají výchozí hodnoty, můžete použít seznam sloupců na INSERT prohlášení, jako je to:

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;

To šetří psaní, dokumentuje, do kterých sloupců skutečně vkládáte hodnoty, a izoluje váš INSERT výpis z fyzického pořadí sloupců ve zdrojové a cílové tabulce.

Poté, jakmile dokončíte CURSOR c1 smyčky, nezkracujte tabulku nebo přijdete o všechnu práci, kterou jste právě udělali! TRUNCATE TABLE odstraní všechny řádky aktuálně v tabulce a používá se zde k vymazání výsledků předchozího spuštění.

A konečně, dvě smyčky musí mít různé štítky, řekněme fetch_loop_1 a fetch_loop_2 . Budete také muset resetovat accum a end_of_cursor před vstupem do druhé smyčky. V tomto případě se však domnívám, že můžeme dělat vše v jedné smyčce s jedním kurzorem, což zjednodušuje kód a tím i údržbu.

Zde je úplný postup:

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 ;

To by mělo fungovat. Pokud někdo najde chybu, rozhodně na ni upozorněte.

EDIT:Právě jsem přidal nějaký kód pro ilustraci, jak se chránit před nulami přicházejícími ze zdrojové tabulky a jak se vyhnout dělení nulou ve výpočtu ERA.

EDIT:Změnil jsem zpět na své původní názvy sloupců a tabulek, abych snížil svůj vlastní zmatek.

UPRAVIT:Kód změněn tak, aby odpovídal odpovědi na Jak mohu přidat sloupec do pracovní tabulky pomocí nové uložené procedury




  1. Jak mohu importovat data do databáze mysql přes pracovní plochu mysql?

  2. MySQL S klauzulí

  3. Oracle Cloud:Vytvoření databáze ATP (Autonomous Transaction Processing).

  4. pravé spojení versus levé spojení