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

MySQL 游標完整指南:從基礎語法到三種循環實戰

     編輯:MySQL 綜合教學

什麼是 MySQL 游標?

游標是一種在存儲過程中逐行處理結果集的機制。它允許開發者聲明一個結果集,打開它,逐行讀取(FETCH),並在循環中對每行數據進行業務邏輯處理,最後關閉釋放資源。MySQL 游標僅能在存儲過程、函數和觸發器中使用,且為只讀、單向、不可滾動。

核心組件與聲明順序

嚴格遵循以下聲明順序,否則會報錯:

  1. 變量聲明(DECLARE):接收列值的局部變量、控制標誌變量。
  2. 游標聲明(DECLARE ... CURSOR FOR SELECT ...):綁定查詢語句。
  3. 異常處理器聲明(DECLARE ... HANDLER FOR NOT FOUND ...):定義無數據時的跳出邏輯。

三種主流循環模式對比

1. WHILE 循環 —— 最經典、通用性最強

CREATE PROCEDURE useCursor()
BEGIN
    DECLARE tmpName VARCHAR(20) DEFAULT '';
    DECLARE allName VARCHAR(255) DEFAULT '';
    DECLARE cur1 CURSOR FOR SELECT name FROM test.level;
    DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET tmpName = NULL;

    OPEN cur1;
    FETCH cur1 INTO tmpName;

    WHILE (tmpName IS NOT NULL) DO
        SET tmpName = CONCAT(tmpName, ';');
        SET allName = CONCAT(allName, tmpName);
        FETCH cur1 INTO tmpName;
    END WHILE;

    CLOSE cur1;
    SELECT allName;
END;

關鍵點:先 FETCH 一次進入循環,循環體末尾再次 FETCH 推進指針;Handler 將 tmpName 置 NULL 觸發退出。

2. LOOP 循環 —— 配合標籤實現精準控制

CREATE PROCEDURE cursor_example()
READS SQL DATA
BEGIN
    DECLARE l_employee_id INT;
    DECLARE l_salary NUMERIC(8,2);
    DECLARE l_department_id INT;
    DECLARE done INT DEFAULT 0;
    DECLARE cur1 CURSOR FOR SELECT employee_id, salary, department_id FROM employees;
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;

    OPEN cur1;
    emp_loop: LOOP
        FETCH cur1 INTO l_employee_id, l_salary, l_department_id;
        IF done = 1 THEN LEAVE emp_loop; END IF;
        -- 處理業務邏輯
    END LOOP emp_loop;
    CLOSE cur1;
END;

優勢:LEAVE 標籤 可跳出多層嵌套循環,邏輯更清晰;done 標誌由 Handler 自動維護。

3. REPEAT 循環 —— 至少執行一次的後測試循環

CREATE PROCEDURE test()
BEGIN
    DECLARE done INT DEFAULT 0;
    DECLARE a VARCHAR(200) DEFAULT '';
    DECLARE c VARCHAR(200) DEFAULT '';
    DECLARE mycursor CURSOR FOR SELECT fusername FROM uchome_friend;
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;

    OPEN mycursor;
    REPEAT
        FETCH mycursor INTO a;
        IF NOT done THEN
            SET c = CONCAT(c, a);
        END IF;
    UNTIL done END REPEAT;
    CLOSE mycursor;
    SELECT c;
END;

注意:REPEAT 會先執行一次 FETCH 再判斷條件,若結果集為空也會執行一次循環體,需配合 IF NOT done 保護業務邏輯。

最佳實踐與避坑指南

  • 必須關閉游標:CLOSE cur1; 釋放內存,否則連接佔用會泄漏。
  • 避免在循環中提交事務:游標操作應在單一事務中完成,或由調用者控制事務邊界。
  • 大數據集慎用:游標屬於行級處理,性能遠低於集合操作(JOIN、子查詢、窗口函數),僅用於無法用集合化 SQL 表達的複雜邏輯。
  • Handler 聲明順序固定:必須在游標聲明之後、OPEN 之前。

總結

MySQL 游標提供了行級處理能力,WHILE 循環 適用於大多數場景,LOOP+標籤 適合嵌套邏輯,REPEAT 適合至少執行一次的場景。實際開發中,優先考慮集合化 SQL,只有在極少數情況下才引入游標。

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