MySQL教程112-MySQL游標的定義及使用


在 MySQL 中,存儲過程或函數中的查詢有時會返回多條記錄,而使用簡單的 SELECT 語句,沒有辦法得到第一行、下一行或前十行的數據,這時可以使用游標來逐條讀取查詢結果集中的記錄。游標在部分資料中也被稱為光標。

關系數據庫管理系統實質是面向集合的,在 MySQL 中並沒有一種描述表中單一記錄的表達形式,除非使用 WHERE 子句來限制只有一條記錄被選中。所以有時我們必須借助於游標來進行單條記錄的數據處理。

一般通過游標定位到結果集的某一行進行數據修改。

結果集是符合 SQL 語句的所有記錄的集合。

其實游標可以看做是一個標識,用來標識數據取到了什么地方,就像是編程語言中數組中的下標。

MySQL 中的游標只能用於存儲過程和函數。

下面介紹游標的使用,主要包括游標的聲明、打開、使用和關閉。

1. 聲明游標

MySQL 中使用 DECLARE 關鍵字來聲明游標,並定義相應的 SELECT 語句,根據需要添加 WHERE 和其它子句。其語法的基本形式如下:

DECLARE cursor_name CURSOR FOR select_statement;

其中,cursor_name 表示游標的名稱;select_statement 表示 SELECT 語句,可以返回一行或多行數據。

例 1

下面聲明一個名為 nameCursor 的游標,代碼如下:

mysql> DELIMITER //
mysql> CREATE PROCEDURE processnames()
    -> BEGIN
    -> DECLARE nameCursor CURSOR
    -> FOR
    -> SELECT name FROM tb_student_info;
    -> END//
Query OK, 0 rows affected (0.07 sec)

以上語句定義了 nameCursor 游標,游標只局限於存儲過程中,存儲過程處理完成后,游標就消失了。

2. 打開游標

聲明游標之后,要想從游標中提取數據,必須首先打開游標。在 MySQL 中,打開游標通過 OPEN 關鍵字來實現,其語法格式如下:

OPEN cursor_name;

其中,cursor_name 表示所要打開游標的名稱。需要注意的是,打開一個游標時,游標並不指向第一條記錄,而是指向第一條記錄的前邊。

在程序中,一個游標可以打開多次。用戶打開游標后,其他用戶或程序可能正在更新數據表,所以有時會導致用戶每次打開游標后,顯示的結果都不同。

3. 使用游標

游標順利打開后,可以使用 FETCH...INTO 語句來讀取數據,其語法形式如下:

FETCH [[NEXT] FROM] cursor_name INTO var_name [, var_name] ...

上述語句中,將游標 cursor_name 中 SELECT 語句的執行結果保存到變量參數 var_name 中。變量參數 var_name 必須在游標使用之前定義。使用游標類似高級語言中的數組遍歷,當第一次使用游標時,此時游標指向結果集的第一條記錄。

MySQL 的游標是只讀的,也就是說,你只能順序地從開始往后讀取結果集,不能從后往前,也不能直接跳到中間的記錄。

4. 關閉游標

游標使用完畢后,要及時關閉,在 MySQL 中,使用 CLOSE 關鍵字關閉游標,其語法格式如下:

CLOSE cursor_name;

CLOSE 釋放游標使用的所有內部內存和資源,因此每個游標不再需要時都應該關閉。

在一個游標關閉后,如果沒有重新打開,則不能使用它。但是,使用聲明過的游標不需要再次聲明,用 OPEN 語句打開它就可以了。

如果你不明確關閉游標,MySQL 將會在到達 END 語句時自動關閉它。游標關閉之后,不能使用 FETCH 來使用該游標。

例 2

創建 users 數據表,並插入數據,SQL 語句和運行結果如下:

mysql> create table if not exists user
    -> (
    -> id int unsigned primary key auto_increment,
-> username varchar(25),
-> userpass varchar(25) -> ); Query OK, 0 rows affected (0.50 sec)
mysql> INSERT INTO users VALUES(null,'sheng','sheng123'),(null,'yu','yu123'),(null,'ling','ling123');
Query OK, 3 rows affected (0.12 sec)

創建存儲過程 test_cursor,並創建游標 cur_test,根據入參uid查詢users返回, 入參沒值默認查詢 users 數據表中的第 2 條記錄,SQL 語句和執行過程如下:

注意: 這里存儲過程中涉及到的控制語句, 在下一章節中有講解, 這里看不懂沒事, 可以看完下一節再回來細品一下!
mysql> \. E:\java\mysql\my.sql

這里我是將存儲過程寫在了本地的一個文件my.sql中, 使用命令\.或source就可以直接調用執行此文件, 即執行文件中的sql, my.sql文件內容如下

delimiter //
create procedure test_cursor(in uid int(4),  out result varchar(30))
begin
    declare name, pass varchar(10);
    declare done int(2);
    declare count int(2) default 0;  
    DECLARE cur_test CURSOR FOR select username, userpass from users;
    declare continue handler for sqlstate '02000' set done=1;
    if uid then select concat_ws(',', result, username, userpass) into result from users where id = uid;  // 如果uid有值直接查詢
    else   // 如果uid沒值
        open cur_test;  // 打開游標
            jkd:loop  // 循環
                fetch cur_test into name, pass;
                set count = count + 1;  // 
                if count = 2 then  // 如果count等於2, 就是第二條數據            
                    select concat_ws(',', name, pass) into result;
                    leave jkd;  // 跳出循環
                end if;
            end loop jkd;            
        close cur_test;
    end if;
end//
delimiter ; 

上面的sql中關於"DECLARE continue handler FOR SQLSTATE '02000' SET done = 1;"的使用, 看這里 -> 說明

創建 update_users() 存儲過程,定義 cursor_update游標,將表 users 中的 user_name 字段全部修改為 入參的值,SQL 語句和執行過程如下。

 source E:\java\mysql\my.sql

my.sql內容如下:

delimiter //
create procedure update_users(in newname varchar(20))
begin
    declare done int(2);
    declare uid int(4);
    declare cursor_update cursor for select id from users;
    declare continue handler for sqlstate '02000' set done=1;
    open cursor_update;
        jkd:loop
            fetch cursor_update into uid;
            update users set username=newname where id=uid;
            if done=1 then
                leave jkd;
            end if;
        end loop jkd;
    close cursor_update;
end//
delimiter ;

調用查看:

mysql> call update_users('test');
Query OK, 0 rows affected (0.26 sec)

mysql> select * from users;
+----+----------+----------+
| id | username | userpass |
+----+----------+----------+
|  1 | test     | sheng123 |
|  2 | test     | yu123    |
|  3 | test     | ling123  |
+----+----------+----------+
3 rows in set (0.00 sec)

mysql> call update_users('test666');
Query OK, 0 rows affected (0.25 sec)

mysql> select * from users;
+----+----------+----------+
| id | username | userpass |
+----+----------+----------+
|  1 | test666  | sheng123 |
|  2 | test666  | yu123    |
|  3 | test666  | ling123  |
+----+----------+----------+
3 rows in set (0.00 sec)

結果顯示,users 表中的 user_name 字段已經全部修改為 入參的值。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM