首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

MySQL 游標完整教學:DECLARE/OPEN/FETCH/CLOSE、NOT FOUND 錯誤處理器、巢狀游標、動態 SQL 預備語句

     編輯:MySQL 資料庫相關知識

MySQL 預存程序游標:從基礎到巢狀與動態 SQL

MySQL 5.0+ 支援游標,**僅限預存程序/函數/觸發器** 中使用,且為**唯讀、單向、不可捲動** (敏感游標)。核心流程:DECLARE → OPEN → FETCH 迴圈 → CLOSE。

1. 基礎游標範本

CREATE PROCEDURE demo_cursor()
BEGIN
  -- 1. 宣告變數
  DECLARE done INT DEFAULT FALSE;
  DECLARE v_seqname VARCHAR(50);
  DECLARE v_value BIGINT;

  -- 2. 宣告游標 (SELECT 不含 INTO)
  DECLARE cur CURSOR FOR SELECT seqname, value FROM sys_sequence;

  -- 3. 宣告 NOT FOUND 錯誤處理器 (關鍵:游標結束觸發)
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

  -- 4. 開啟游標
  OPEN cur;

  -- 5. 迴圈 FETCH
  read_loop: LOOP
    FETCH cur INTO v_seqname, v_value;
    IF done THEN
      LEAVE read_loop;
    END IF;
    -- 處理邏輯
    SELECT v_seqname, v_value;
  END LOOP;

  -- 6. 關閉游標
  CLOSE cur;
END;

2. 關鍵點深度解析

  • DECLARE 順序:變數 → 游標 → 處理器 (處理器需在游標之後,否則編譯錯誤)。
  • NOT FOUND 處理器:游標讀完下一行無資料時觸發,設定旗標 done=TRUE,迴圈判斷退出。**必須宣告**,否則 FETCH 結束拋出錯誤中斷程序。
  • CONTINUE vs EXIT:CONTINUE 執行完處理器繼續後續語句 (配合旗標);EXIT 直接離開當前 BEGIN...END 區塊。
  • 游標唯讀:不可用 UPDATE ... WHERE CURRENT OF cur (MySQL 不支援)。

3. 巢狀游標 (多層迴圈) 實現

利用 BEGIN ... END 區塊隔離變數作用域,每層宣告自己的 done 旗標與 NOT FOUND 處理器 (同一區塊內不可重複宣告同類處理器)。

CREATE PROCEDURE nested_cursor()
BEGIN
  DECLARE done_outer INT DEFAULT FALSE;
  DECLARE v_id INT;
  DECLARE cur_outer CURSOR FOR SELECT id FROM parent_table;
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET done_outer = TRUE;

  OPEN cur_outer;
  outer_loop: LOOP
    FETCH cur_outer INTO v_id;
    IF done_outer THEN LEAVE outer_loop; END IF;

    -- 內層區塊:獨立變數與處理器
    BEGIN
      DECLARE done_inner INT DEFAULT FALSE;
      DECLARE v_child_name VARCHAR(50);
      DECLARE cur_inner CURSOR FOR SELECT name FROM child_table WHERE parent_id = v_id;
      DECLARE CONTINUE HANDLER FOR NOT FOUND SET done_inner = TRUE;

      OPEN cur_inner;
      inner_loop: LOOP
        FETCH cur_inner INTO v_child_name;
        IF done_inner THEN LEAVE inner_loop; END IF;
        SELECT v_id, v_child_name;
      END LOOP;
      CLOSE cur_inner;
    END;
  END LOOP;
  CLOSE cur_outer;
END;

4. 動態 SQL 預備語句 (彌補游標無法動態組裝 SELECT)

游標的 SELECT 必須靜態,若需動態表名/欄位/條件,改用 PREPARE / EXECUTE / DEALLOCATE PREPARE:

CREATE PROCEDURE dynamic_sql(IN tbl_name VARCHAR(64), IN cond_val INT)
BEGIN
  SET @sql = CONCAT('SELECT * FROM `', tbl_name, '` WHERE id > ?');
  PREPARE stmt FROM @sql;
  SET @val = cond_val;
  EXECUTE stmt USING @val;
  DEALLOCATE PREPARE stmt;
END;
  • ? 佔位符對應 USING 變數,防注入。
  • 多參數:USING @a, @b, @c。
  • 預備語句生命週期:Session 級,連線關閉或 DEALLOCATE 釋放。

5. 實戰建議

  • 游標處理**逐行邏輯複雜、需事務控制** 的場景 (如發送通知、呼叫外部 API、複雜計算)。
  • 集合操作 (單條 SQL) 效能遠超游標,**能用 SQL 解決絕不用游標**。
  • 大量資料游標處理易超時,分批處理、加 LIMIT、調大 max_execution_time。
  • 除錯:SELECT ... INTO @var 觀察中間值,或寫入臨時表/日誌表。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved