Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Wie kann ich zwei Prozeduren in einer kombinieren, um eine Tabelle zu füllen, anstatt dass jede der beiden Prozeduren ihre eigene Tabelle füllt?

Recht; Mal sehen, was wir hier haben.

Zuerst muss der Code wie folgt blockiert werden:

variable declarations
cursor declarations
handler declarations
everything else

Also Ihr DECLARE CURSOR c2 muss erscheinen zwischen DECLARE CURSOR c1 und DECLARE CONTINUE HANDLER . Außerdem benötigen Sie nur einen CONTINUE HANDLER weil es vom Zeitpunkt der Deklaration bis zum Ende des Verfahrens gilt.

Als nächstes kommt die Anweisung

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

Die benannten Spalten im SELECT -Klausel sind die Spalten, aus denen Sie auswählen nicht diejenigen, in die Sie einfügen also müssen sie Spalten in der Tabelle starting_pitchers_game_log sein . Auch da die Spalten nicht aus starting_pitchers_game_log kopiert werden (also ip_total , er_total und era ) alle Standardwerte haben, könnten Sie eine Spaltenliste für INSERT verwenden Anweisung, etwa so:

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;

Das erspart Tipparbeit, dokumentiert, in welche Spalten Sie tatsächlich Werte einfügen und isoliert Ihr INSERT Aussage über die physische Reihenfolge der Spalten in den Quell- und Zieltabellen.

Als nächstes, sobald Sie den CURSOR c1 beendet haben loop, die Tabelle nicht abschneiden oder Sie verlieren die ganze Arbeit, die Sie gerade getan haben! TRUNCATE TABLE löscht alle derzeit in der Tabelle befindlichen Zeilen und wird hier verwendet, um die Ergebnisse des vorherigen Laufs zu löschen.

Schließlich müssen die beiden Schleifen unterschiedliche Bezeichnungen haben, sagen wir fetch_loop_1 und fetch_loop_2 . Sie müssten auch accum zurücksetzen und end_of_cursor vor dem Eintritt in die zweite Schleife. Ich glaube jedoch, dass wir in diesem Fall alles in einer Schleife mit einem Cursor erledigen können, was den Code einfacher und damit leichter zu warten macht.

Hier ist das vollständige Verfahren:

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 ;

Das sollte funktionieren. Wenn jemand einen Fehler findet, bitte auf jeden Fall darauf hinweisen.

BEARBEITEN:Ich habe gerade etwas Code hinzugefügt, um zu veranschaulichen, wie man sich vor Nullen aus der Quelltabelle schützt und wie man eine Division durch Null bei der ERA-Berechnung vermeidet.

BEARBEITEN:Ich habe zu meinen ursprünglichen Spalten- und Tabellennamen zurückgeändert, um meine eigene Verwirrung zu verringern.

BEARBEITEN:Code geändert, um mit der Antwort auf Wie kann ich mit einer neuen gespeicherten Prozedur eine Spalte zu einer Arbeitstabelle hinzufügen