游標用於在預存程序中逐行處理查詢結果集,適合複雜邏輯、逐行計算、動態 SQL 構建等場景。
DECLARE cursor_name CURSOR FOR SELECT ...;DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;OPEN cursor_name;FETCH cursor_name INTO var1, var2...;WHILE NOT done DO ... END WHILE; 或 LOOP ... END LOOP;CLOSE cursor_name;DROP PROCEDURE IF EXISTS useCursor;
DELIMITER $$
CREATE PROCEDURE useCursor()
BEGIN
DECLARE tmpName VARCHAR(20) DEFAULT '';
DECLARE allName VARCHAR(255) DEFAULT '';
DECLARE done INT DEFAULT 0;
DECLARE cur1 CURSOR FOR SELECT name FROM test.level;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN cur1;
FETCH cur1 INTO tmpName;
WHILE NOT done DO
SET tmpName = CONCAT(tmpName, ';');
SET allName = CONCAT(allName, tmpName);
FETCH cur1 INTO tmpName;
END WHILE;
CLOSE cur1;
SELECT allName AS result;
END$$
DELIMITER ;
CALL useCursor();
DELIMITER $$
DROP PROCEDURE IF EXISTS cursor_example$$
CREATE PROCEDURE cursor_example()
READS SQL DATA
BEGIN
DECLARE l_employee_id INT;
DECLARE l_salary DECIMAL(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;
-- 處理邏輯:如動態構建 SQL、寫入臨時表等
END LOOP emp_loop;
CLOSE cur1;
END$$
DELIMITER ;
DELIMITER //
DROP PROCEDURE IF EXISTS test //
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 //
DELIMITER ;
| 項目 | 說明 |
|---|---|
| 作用域 | 游標僅在預存程序/函數/觸發器中可用,不可在普通 SQL 使用。 |
| 唯讀/敏感度 | MySQL 游標為非捲動、唯讀、敏感(反映開啟時的資料快照,或即時變更視存儲引擎而定)。 |
| FETCH 後必須檢查 NOT FOUND | 否則迴圈無法終止,導致無限迴圈或例外。 |
| 巢狀游標 | 支援,內層游標在外層迴圈中 OPEN/FETCH/CLOSE,注意變數名不衝突。 |
| 效能 | 逐行處理遠慢於集合操作(JOIN/子查詢/窗口函數),能用單條 SQL 解決盡量不用游標。 |
INSERT ... SELECT, UPDATE ... JOIN, MERGE (8.0+)ROW_NUMBER(), LAG(), SUM() OVER() 等