游標是一種在存儲過程中逐行處理結果集的機制。它允許開發者聲明一個結果集,打開它,逐行讀取(FETCH),並在循環中對每行數據進行業務邏輯處理,最後關閉釋放資源。MySQL 游標僅能在存儲過程、函數和觸發器中使用,且為只讀、單向、不可滾動。
嚴格遵循以下聲明順序,否則會報錯:
DECLARE):接收列值的局部變量、控制標誌變量。DECLARE ... CURSOR FOR SELECT ...):綁定查詢語句。DECLARE ... HANDLER FOR NOT FOUND ...):定義無數據時的跳出邏輯。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 觸發退出。
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 自動維護。
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; 釋放內存,否則連接佔用會泄漏。OPEN 之前。MySQL 游標提供了行級處理能力,WHILE 循環 適用於大多數場景,LOOP+標籤 適合嵌套邏輯,REPEAT 適合至少執行一次的場景。實際開發中,優先考慮集合化 SQL,只有在極少數情況下才引入游標。