萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 程式設計 >  >> 資料庫 >> MySQL 教學

MySQL 游標 (Cursor) 完整參考手冊:語法、操作與實戰範例

什麼是游標?

游標 是預存程序/函數/觸發器中,用於逐行處理查詢結果集的資料庫物件。MySQL 游標特性:

  • 唯讀:無法透過游標修改底層資料
  • 向前:只能順序讀取,不支援捲動(Scrollable)
  • 非保持:對基底表變更的敏感度取決於隔離層級

核心語法速查表

陳述式語法用途
宣告DECLARE cursor_name CURSOR FOR SELECT_statement;定義游標對應的查詢
開啟OPEN cursor_name;執行查詢、建立結果集
擷取FETCH cursor_name INTO var_list;取得當前列並移至下一列
關閉CLOSE cursor_name;釋放記憶體資源

必要元件:NOT FOUND Handler

因為 MySQL 游標無 %NOTFOUND 屬性,必須宣告 CONTINUE HANDLER FOR NOT FOUND 來偵測結束:

DECLARE done INT DEFAULT FALSE;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

完整範例一:函數中使用游標彙總城市清單

DELIMITER //
CREATE FUNCTION city_list() RETURNS VARCHAR(255)
BEGIN
    DECLARE done INT DEFAULT FALSE;
    DECLARE v_city VARCHAR(50);
    DECLARE v_result VARCHAR(255) DEFAULT '';
    DECLARE cur CURSOR FOR SELECT city FROM employee;
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

    OPEN cur;
    read_loop: LOOP
        FETCH cur INTO v_city;
        IF done THEN LEAVE read_loop; END IF;
        SET v_result = CONCAT(v_result, ', ', v_city);
    END LOOP;
    CLOSE cur;
    RETURN SUBSTR(v_result, 3);  -- 移除開頭逗號
END//
DELIMITER ;

SELECT city_list();  -- Toronto, Vancouver, Vancouver, ...

完整範例二:預存程序中使用 WHILE 迴圈逐列處理

DELIMITER $$
CREATE PROCEDURE process_employees()
BEGIN
    DECLARE done INT DEFAULT FALSE;
    DECLARE v_id INT;
    DECLARE v_name VARCHAR(30);
    DECLARE v_city VARCHAR(30);
    DECLARE cur CURSOR FOR SELECT id, first_name, city FROM employee;
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

    OPEN cur;
    read_loop: WHILE NOT done DO
        FETCH cur INTO v_id, v_name, v_city;
        IF done THEN LEAVE read_loop; END IF;
        -- 這裡處理單列商業邏輯,例如:
        SELECT v_id, v_name, v_city;  -- 示範輸出
    END WHILE;
    CLOSE cur;
END$$
DELIMITER ;

CALL process_employees();

進階技巧與注意事項

1. 巢狀游標

外層游標迴圈中可開啟內層游標,但每個游標都需獨立的 Handler 變數,否則內層結束會誤觸發外層結束。

2. 游標與動態 SQL

MySQL 不支援 PREPARE 產生的陳述式直接作為游標來源,需先建立暫存表再對暫存表開啟游標。

3. 效能考量

  • 游標屬 RBAR (Row-By-Agonizing-Row) 模式,大量資料建議改用集合式 SQL(JOIN、窗格函數、CTE)
  • 僅在必須逐列執行外部動作(如呼叫外部 API、發送郵件、複雜程序邏輯)時使用

4. 版本相容性

語法自 MySQL 5.0 起支援,MariaDB 完全相容。MySQL 8.0+ 建議搭配 DECLARE ... CURSOR FOR EXECUTE stmt 使用預處理陳述式。

建立測試資料表腳本

CREATE TABLE employee (
    id INT, first_name VARCHAR(15), last_name VARCHAR(15),
    start_date DATE, end_date DATE, salary FLOAT(8,2),
    city VARCHAR(10), description VARCHAR(15)
);
INSERT INTO employee VALUES
(1,'Jason','Martin','1996-07-25','2006-07-25',1234.56,'Toronto','Programmer'),
(2,'Alison','Mathews','1976-03-21','1986-02-21',6661.78,'Vancouver','Tester'),
(3,'James','Smith','1978-12-12','1990-03-15',6544.78,'Vancouver','Tester'),
(4,'Celia','Rice','1982-10-24','1999-04-21',2344.78,'Vancouver','Manager'),
(5,'Robert','Black','1984-01-15','1998-08-08',2334.78,'Vancouver','Tester'),
(6,'Linda','Green','1987-07-30','1996-01-04',4322.78,'New York','Tester'),
(7,'David','Larry','1990-12-31','1998-02-12',7897.78,'New York','Manager'),
(8,'James','Cat','1996-09-17','2002-04-15',1232.78,'Vancouver','Tester');

掌握游標語法與 Handler 模式,即可在預存程序中實現複雜的逐列邏輯,但請記住:能用集合式 SQL 解決的,就不要用游標。

copyright © 萬盛學電腦網 all rights reserved