Mysql
 sql >> Teknologi Basis Data >  >> RDS >> Mysql

Bagaimana saya bisa menggabungkan dua prosedur dalam satu untuk mengisi satu tabel daripada masing-masing dari dua prosedur yang mengisi tabel itu sendiri?

Benar; mari kita lihat apa yang kita miliki di sini.

Pertama, kode harus diblokir sebagai berikut:

variable declarations
cursor declarations
handler declarations
everything else

Jadi DECLARE CURSOR c2 Anda harus muncul di antara DECLARE CURSOR c1 dan DECLARE CONTINUE HANDLER . Selain itu, Anda hanya perlu satu CONTINUE HANDLER karena berlaku mulai dari deklarasi hingga akhir prosedur.

Berikutnya adalah pernyataan

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

Kolom bernama di SELECT klausa adalah kolom yang Anda pilih, tidak yang Anda masukkan, jadi harus berupa kolom dalam tabel starting_pitchers_game_log . Juga, karena kolom tidak disalin dari starting_pitchers_game_log (yaitu, ip_total , er_total dan era ) semua memiliki nilai default, Anda dapat menggunakan daftar kolom di INSERT pernyataan, seperti:

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;

Ini menghemat pengetikan, mendokumentasikan kolom yang sebenarnya Anda masukkan nilai dan mengisolasi INSERT Anda pernyataan dari urutan fisik kolom di tabel sumber dan target.

Selanjutnya, setelah Anda menyelesaikan CURSOR c1 loop, jangan potong tabel atau Anda akan kehilangan semua pekerjaan yang baru saja Anda lakukan! TRUNCATE TABLE menghapus semua baris yang saat ini ada di tabel, dan digunakan di sini untuk menghapus hasil dari proses sebelumnya.

Terakhir, kedua loop harus memiliki label yang berbeda, misalnya fetch_loop_1 dan fetch_loop_2 . Anda juga perlu mengatur ulang accum dan end_of_cursor sebelum memasuki putaran kedua. Namun, dalam kasus ini saya yakin kita dapat melakukan semuanya dalam satu loop dengan satu kursor, yang membuat kode lebih sederhana dan dengan demikian lebih mudah untuk dipelihara.

Berikut prosedur lengkapnya:

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 ;

Itu harus melakukan pekerjaan. Jika ada yang menemukan bug, mohon tunjukkan.

EDIT:Saya baru saja menambahkan beberapa kode untuk mengilustrasikan bagaimana melindungi dari nol yang berasal dari tabel sumber, dan bagaimana menghindari pembagian dengan nol pada perhitungan ERA.

EDIT:Saya telah mengubah kembali ke nama kolom dan tabel asli saya untuk mengurangi kebingungan saya sendiri.

EDIT:Kode diubah agar konsisten dengan jawaban untuk Bagaimana cara menambahkan kolom ke tabel kerja menggunakan prosedur tersimpan baru




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Cara lain untuk meningkatkan SQL Query untuk menghindari penyatuan?

  2. PHP Peringatan:PHP Startup:Tidak dapat memuat perpustakaan dinamis '/usr/lib/php/20151012/msqli.so'

  3. Lebih memahami masalah `yield_per()` SQLalchemy

  4. Urutan Alfanumerik Oleh di Mysql

  5. Cara menghapus baris duplikat dari tabel MySQL