Mysql
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Mysql

Làm cách nào tôi có thể kết hợp hai thủ tục trong một để điền vào một bảng thay vì mỗi thủ tục trong hai thủ tục điền vào bảng của chính nó?

Đúng; hãy xem những gì chúng tôi có ở đây.

Đầu tiên, mã phải bị chặn như sau:

variable declarations
cursor declarations
handler declarations
everything else

Vì vậy, DECLARE CURSOR c2 của bạn phải xuất hiện giữa DECLARE CURSOR c1DECLARE CONTINUE HANDLER . Ngoài ra, bạn chỉ cần một CONTINUE HANDLER bởi vì nó có hiệu lực từ thời điểm khai báo cho đến khi kết thúc thủ tục.

Tiếp theo là câu lệnh

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

Các cột được đặt tên trong SELECT mệnh đề là các cột bạn đang chọn, không những cái bạn đang chèn vào, vì vậy chúng phải là các cột trong bảng starting_pitchers_game_log . Ngoài ra, vì các cột không được sao chép từ starting_pitchers_game_log (nghĩa là, ip_total , er_totalera ) tất cả đều có giá trị mặc định, bạn có thể sử dụng danh sách cột trên INSERT tuyên bố, như vậy:

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;

Điều này giúp tiết kiệm việc nhập, tài liệu mà các cột bạn đang thực sự chèn giá trị vào và cách ly INSERT của bạn câu lệnh từ thứ tự vật lý của các cột trong bảng nguồn và bảng đích.

Tiếp theo, khi bạn hoàn thành CURSOR c1 vòng lặp, không cắt ngắn bảng hoặc bạn sẽ mất tất cả công việc bạn vừa làm! TRUNCATE TABLE xóa tất cả các hàng hiện có trong bảng và được sử dụng ở đây để xóa kết quả của lần chạy trước đó.

Cuối cùng, hai vòng lặp phải có các nhãn khác nhau, chẳng hạn như fetch_loop_1fetch_loop_2 . Bạn cũng cần đặt lại accumend_of_cursor trước khi vào vòng lặp thứ hai. Tuy nhiên, trong trường hợp này, tôi tin rằng chúng ta có thể thực hiện mọi thứ trong một vòng lặp với một con trỏ, điều này làm cho mã đơn giản hơn và do đó dễ bảo trì hơn.

Đây là quy trình hoàn chỉnh:

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 ;

Điều đó sẽ thực hiện công việc. Nếu có ai đó tìm thấy lỗi, xin vui lòng chỉ ra.

CHỈNH SỬA:Tôi vừa thêm một số mã để minh họa cách bảo vệ khỏi các giá trị rỗng đến từ bảng nguồn và cách tránh chia hết cho 0 trong phép tính ERA.

CHỈNH SỬA:Tôi đã thay đổi lại tên cột và bảng ban đầu của mình để giảm sự nhầm lẫn của chính tôi.

CHỈNH SỬA:Mã đã thay đổi để phù hợp với câu trả lời cho Làm cách nào để thêm cột vào bảng công việc bằng thủ tục mới được lưu trữ




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Quản lý tài khoản người dùng, vai trò, quyền, xác thực PHP và MySQL

  2. Mã Django hoặc trình kích hoạt MySQL

  3. MySQL DROP CONSTRAINT DUY NHẤT

  4. Cách tạo truy vấn trong Drupal 8

  5. Làm thế nào để chèn các ký tự đặc biệt vào cơ sở dữ liệu?