游標是存儲過程中用於逐行處理結果集的機制。MySQL 游標具有只讀、單向、不可滾動特性,適用於需要逐行邏輯處理的場景,如複雜數據轉換、批量業務邏輯執行等。
-- 1. 聲明游標
DECLARE cursor_name CURSOR FOR SELECT_statement;
-- 2. 聲明處理器(異常捕獲)
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
-- 3. 打開游標
OPEN cursor_name;
-- 4. 獲取數據
FETCH cursor_name INTO var1, var2, ...;
-- 5. 關閉游標
CLOSE cursor_name;
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,通過 handler 將 NOT FOUND 轉為變量 NULL 終止循環。
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;
優勢:結構清晰,FETCH 與判斷緊湊結合,標籤支持嵌套循環控制。
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;
特點:至少執行一次 FETCH,適合確定有數據的場景。
READS SQL DATA 特性聲明提升優化器判斷CLOSE 釋放資源,避免連接洩漏| 錯誤現象 | 原因 | 解決 |
|---|---|---|
| Cursor fetch returns no data | 未聲明 handler 或邏輯錯誤 | 檢查 CONTINUE HANDLER 聲明 |
| Variables not updated | FETCH INTO 變量順序/類型不匹配 | 核對聲明順序與 SELECT 列 |
| Infinite loop | 缺少 FETCH 或 handler 未生效 | 確保循環體內有 FETCH,handler 正確設置 |