首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> MySQL 資料庫 >> MySQL 綜合教學

MySQL 游標使用詳解:聲明、遍歷、處理器與實戰案例

     編輯:MySQL 綜合教學

MySQL 游標使用詳解:聲明、遍歷、處理器與實戰案例

游標是存儲過程中逐行處理結果集的機制,類似指針或數組下標。雖然功能強大,但逐行處理效率低、增加服務器負擔,生產環境能用集合操作 (JOIN、子查詢、窗口函數) 解決的堅決不用游標。

一、語法結構與聲明順序

CREATE PROCEDURE proc_name()
BEGIN
    -- 1. 變量聲明 (必須在游標之前)
    DECLARE var_name data_type [DEFAULT value];

    -- 2. 條件/處理器聲明 (可選,但在游標之前)
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;

    -- 3. 游標聲明 (在變量/處理器之後,業務邏輯之前)
    DECLARE cursor_name CURSOR FOR SELECT_statement;

    -- 4. 業務邏輯
    OPEN cursor_name;
    FETCH cursor_name INTO var_list;
    WHILE done <> 1 DO
        -- 處理當前行
        FETCH cursor_name INTO var_list;
    END WHILE;
    CLOSE cursor_name;
END

鐵律:聲明順序 — 變量 → 條件/處理器 → 游標 → 業務代碼。違序報錯。

二、核心操作命令

命令作用
DECLARE c CURSOR FOR SELECT ...定義游標關聯的結果集 (不執行查詢)
OPEN c執行查詢,建立結果集,指針指向第一行之前
FETCH c INTO var1, var2...移動指針到下一行,將列值賦給變量。無數據時觸發 NOT FOUND
CLOSE c釋放游標佔用的資源,**必須顯式關閉**

三、循環遍歷三種寫法

1. WHILE 循環 (最常用)

DECLARE done INT DEFAULT 0;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;

OPEN cur;
FETCH cur INTO v1, v2;
WHILE done <> 1 DO
    -- 處理 v1, v2
    FETCH cur INTO v1, v2;
END WHILE;
CLOSE cur;

2. LOOP ... END LOOP

OPEN cur;
read_loop: LOOP
    FETCH cur INTO v1, v2;
    IF done = 1 THEN LEAVE read_loop; END IF;
    -- 處理
END LOOP;
CLOSE cur;

3. REPEAT ... UNTIL

OPEN cur;
REPEAT
    FETCH cur INTO v1, v2;
    IF done <> 1 THEN
        -- 處理
    END IF;
UNTIL done = 1 END REPEAT;
CLOSE cur;

四、實戰案例:統計薪資 > 999 的員工人數

DELIMITER $$

CREATE PROCEDURE count_high_salary(OUT total INT)
BEGIN
    DECLARE v_sal INT;
    DECLARE done INT DEFAULT 0;
    DECLARE cur CURSOR FOR SELECT sal FROM employee WHERE sal IS NOT NULL;
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;

    SET total = 0;
    OPEN cur;
    FETCH cur INTO v_sal;
    WHILE done <> 1 DO
        IF v_sal > 999 THEN
            SET total = total + 1;
        END IF;
        FETCH cur INTO v_sal;
    END WHILE;
    CLOSE cur;
END$$

DELIMITER ;

-- 調用
CALL count_high_salary(@cnt);
SELECT @cnt;  -- 結果: 13

五、進階:嵌套游標與動態 SQL

游標不支持動態 SQL (無法用準備語句定義)。若需動態,只能在應用層拼裝 SQL 後調用存儲過程,或用臨時表中轉。

六、性能警示與替代方案

  1. 逐行 = 慢:10 萬行數據,游標需 10 萬次 FETCH + 上下文切換,集合操作毫秒級完成。
  2. 避免游標中 JOIN/子查詢:嵌套查詢放大性能災難。
  3. 替代方案優先級:
    1. 單條 SQL (聚合、窗口函數、CTE、JOIN)
    2. 臨時表 + 批量 UPDATE/INSERT
    3. 應用層分批處理 (編程語言游標/流式讀取)
    4. 不得已才用服務端游標

七、總結

游標是 MySQL 存儲過程的「最後手段」。掌握聲明順序、處理器機制、三種循環寫法、必須 CLOSE,但生產代碼中應極力避免。遇到「必須逐行處理」的場景,先思考:能否用 ROW_NUMBER()、LAG/LEAD、JSON_TABLE、INSERT ... SELECT 等集合化方式解決?

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved