Mysql
 sql >> база данни >  >> RDS >> Mysql

Как мога да комбинирам две процедури в една, за да попълня една таблица, а не всяка от двете процедури да попълва собствената си таблица?

Право; нека да видим какво имаме тук.

Първо, кодът трябва да бъде блокиран, както следва:

variable declarations
cursor declarations
handler declarations
everything else

Така че вашият DECLARE CURSOR c2 трябва се появяват между DECLARE CURSOR c1 и DECLARE CONTINUE HANDLER . Освен това имате нужда само от един CONTINUE HANDLER защото влиза в сила от момента на деклариране до края на процедурата.

Следва изявлението

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

Именуваните колони в SELECT клаузата са колоните, от които избирате, не тези, в които вмъквате, така че те трябва да бъдат колони в таблицата starting_pitchers_game_log . Освен това, тъй като колоните не се копират от starting_pitchers_game_log (тоест ip_total , er_total и era ) всички имат стойности по подразбиране, можете да използвате списък с колони в INSERT изявление, така:

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;

Това спестява въвеждане, документи в кои колони всъщност вмъквате стойности и изолира вашия INSERT оператор от физическия ред на колоните в изходната и целевата таблица.

След това, след като завършите CURSOR c1 цикъл, не съкращавайте таблицата или ще загубите цялата работа, която току-що сте свършили! TRUNCATE TABLE изтрива всички редове в таблицата в момента и се използва тук за изчистване на резултатите от предишното изпълнение.

И накрая, двата цикъла трябва да имат различни етикети, кажете fetch_loop_1 и fetch_loop_2 . Ще трябва също да нулирате accum и end_of_cursor преди да влезете във втория цикъл. Въпреки това, в този случай вярвам, че можем да направим всичко в един цикъл с един курсор, което прави кода по-опростен и по този начин по-лесен за поддръжка.

Ето пълната процедура:

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 ;

Това трябва да свърши работа. Ако някой открие грешка, моля да я посочи.

РЕДАКТА

РЕДАКТИРАНЕ:Промених се обратно към оригиналните си имена на колони и таблици, за да намаля собственото си объркване.

РЕДАКТИРАНЕ:Кодът е променен, за да бъде в съответствие с отговора на Как мога да добавя колона към работна таблица с помощта на нова съхранена процедура




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Mytop – Полезен инструмент за наблюдение на производителността на MySQL/MariaDB в Linux

  2. MySQL:Разширете диапазона от време в нови редове

  3. Производителност на пакетно вмъкване на JDBC

  4. Разрешения за MySQL Съхранена процедура

  5. Въпросителни знаци на MySQL db вместо знаци на иврит..?