MySQL游標(biāo)的介紹與使用
定義
游標(biāo)(Cursor)是處理數(shù)據(jù)的一種方法,為了查看或者處理結(jié)果集中的數(shù)據(jù),游標(biāo)提供了在結(jié)果集中一次一行遍歷數(shù)據(jù)的能力。
游標(biāo)也是一種面向過程的 sql 編程方法,所以一般在存儲過程、函數(shù)、觸發(fā)器、循環(huán)處理中使用。
游標(biāo)主要用于交互式應(yīng)用,其中用戶需要滾動屏幕上的數(shù)據(jù),并對數(shù)據(jù)進(jìn)行瀏覽或做出更改。
游標(biāo)的作用
游標(biāo)相當(dāng)于一個指針,這個指針指向 select 的第一行數(shù)據(jù),可以通過移動指針來遍歷后面的數(shù)據(jù)。
游標(biāo)是對查詢出來的結(jié)果集作為一個單元來有效的處理。
游標(biāo)可以定在該單元中的特定行,從結(jié)果集的當(dāng)前行檢索一行或多行。
可以對結(jié)果集當(dāng)前行做修改。
一般不使用游標(biāo),但是需要逐條處理數(shù)據(jù)的時候,游標(biāo)顯得十分重要。
游標(biāo)的使用
在mysql中,游標(biāo)可以在存儲過程、函數(shù)、觸發(fā)器和事件中使用。
游標(biāo)需要與相關(guān) handler 一起使用,并在 handler 之前定義。
游標(biāo)有以下三個屬性:
- Asensitive: 數(shù)據(jù)庫也可以選擇不復(fù)制結(jié)果集
- Read only: 不可更新,只讀
- Nonscrollable: 游標(biāo)只能向一個方向前進(jìn),并且不可以跳過任何一行數(shù)據(jù)。
聲明游標(biāo):
創(chuàng)建一個游標(biāo),并指定這個游標(biāo)需要遍歷的select查詢,聲明游標(biāo)時并不會去執(zhí)行這個sql。
打開游標(biāo):
打開游標(biāo)的時候,會執(zhí)行游標(biāo)對應(yīng)的select語句。
遍歷數(shù)據(jù):
使用游標(biāo)循環(huán)遍歷select結(jié)果中每一行數(shù)據(jù),然后進(jìn)行處理。
業(yè)務(wù)操作:
對遍歷到的每行數(shù)據(jù)進(jìn)行操作的過程,可以放置任何需要執(zhí)行的執(zhí)行的語句(增刪改查):這里視具體情況而定。
關(guān)閉游標(biāo):
游標(biāo)使用完之后一定要釋放(游標(biāo)占用的內(nèi)存還是有點(diǎn)大的)。
注:使用的臨時字段需要在定義游標(biāo)之前進(jìn)行聲明。
游標(biāo)語法
游標(biāo)的使用過程:聲明游標(biāo)、打開游標(biāo)、遍歷游標(biāo)、關(guān)閉游標(biāo)
聲明游標(biāo):DECLARE 游標(biāo)名稱 CURSOR FOR 查詢語句;
打開游標(biāo):open 游標(biāo)名稱;
遍歷游標(biāo):fetch 游標(biāo)名稱 into 變量列表;
取出當(dāng)前行的結(jié)果,將結(jié)果放在對應(yīng)的變量中,并將游標(biāo)指針指向下一行的數(shù)據(jù)。
當(dāng)調(diào)用 fetch 的時候,會獲取當(dāng)前行的數(shù)據(jù),如果當(dāng)前行無數(shù)據(jù),會引發(fā) mysql 內(nèi)部的 NOT FOUND 錯誤。
關(guān)閉游標(biāo):close 游標(biāo)名稱;
游標(biāo)使用完畢之后一定要關(guān)閉。
條件處理
DECLARE CONTINE HANDLER 表達(dá)式 1 SET 表達(dá)式 2:
這段代碼的作用是定義一個 CONTINE HANDLER,這個的作用是當(dāng)表達(dá)式 1 的條件出現(xiàn)時,將執(zhí)行表達(dá)式 2 的語句。
用這個語句可以實(shí)現(xiàn)條件的變更實(shí)質(zhì)是利用 mysql 的異常處理,也常常在游標(biāo)上使用,來輔助判斷游標(biāo)數(shù)據(jù)是否遍歷完了。
例如 DECLARE CONTINUE HANDLER FOR NOT FOUND …
的語句,這是為了對游標(biāo)沒有下一條記錄可供訪問的情況做出異常處理。
創(chuàng)建表-test1-test2-test3
DROP TABLE IF EXISTS test1; CREATE TABLE test1(a int,b int); INSERT INTO test1 VALUES (1,2),(3,4),(5,6); DROP TABLE IF EXISTS test2; CREATE TABLE test2(a int); INSERT INTO test2 VALUES (100),(200),(300); DROP TABLE IF EXISTS test3; CREATE TABLE test3(b int); INSERT INTO test3 VALUES (400),(500),(600);
寫一個函數(shù),計算 test1 表中 a、b 字段所有的和
/*刪除函數(shù)*/ DROP FUNCTION IF EXISTS fun1; /*聲明結(jié)束符為$*/ DELIMITER $ /*創(chuàng)建函數(shù)*/ CREATE FUNCTION fun1(v_max_a int) RETURNS int BEGIN /*用于保存結(jié)果*/ DECLARE v_total int DEFAULT 0; /*創(chuàng)建一個變量,用來保存當(dāng)前行中a的值*/ DECLARE v_a int DEFAULT 0; /*創(chuàng)建一個變量,用來保存當(dāng)前行中b的值*/ DECLARE v_b int DEFAULT 0; /*創(chuàng)建游標(biāo)結(jié)束標(biāo)志變量*/ DECLARE v_done int DEFAULT FALSE; /*創(chuàng)建游標(biāo)*/ DECLARE cur_test1 CURSOR FOR SELECT a,b from test1 where a<=v_max_a; /*設(shè)置游標(biāo)結(jié)束時v_done的值為true,可以v_done來判斷游標(biāo)是否結(jié)束了*/ DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done=TRUE; /*設(shè)置v_total初始值*/ SET v_total = 0; /*打開游標(biāo)*/ OPEN cur_test1; /*使用Loop循環(huán)遍歷游標(biāo)*/ a:LOOP /*先獲取當(dāng)前行的數(shù)據(jù),然后將當(dāng)前行的數(shù)據(jù)放入v_a,v_b中,如果當(dāng)前行無數(shù)據(jù),v_done會被置 為true*/ FETCH cur_test1 INTO v_a, v_b; /*通過v_done來判斷游標(biāo)是否結(jié)束了,退出循環(huán)*/ if v_done THEN LEAVE a; END IF; /*對v_total值累加處理*/ SET v_total = v_total + v_a + v_b; END LOOP; /*關(guān)閉游標(biāo)*/ CLOSE cur_test1; /*返回結(jié)果*/ RETURN v_total; END $ /*結(jié)束符置為;*/ DELIMITER ;
其中 DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done=TRUE;
是異常處理的語法,意思是當(dāng)遇到 NOT FOUND 錯誤時,將 v_done 設(shè)為 ture,continue 繼續(xù)執(zhí)行當(dāng)前任務(wù)。
測試
mysql> select * from test1; +------+------+ | a | b | +------+------+ | 1 | 2 | | 3 | 4 | | 5 | 6 | +------+------+ 3 rows in set (0.00 sec) mysql> select fun1(1); +---------+ | fun1(1) | +---------+ | 3 | +---------+ 1 row in set (0.00 sec) mysql> select fun1(4); +---------+ | fun1(4) | +---------+ | 10 | +---------+ 1 row in set (0.00 sec) mysql> select * from test1; +------+------+ | a | b | +------+------+ | 1 | 2 | | 3 | 4 | | 5 | 6 | +------+------+ 3 rows in set (0.00 sec) mysql> select fun1(5); +---------+ | fun1(5) | +---------+ | 21 | +---------+ 1 row in set (0.00 sec)
游標(biāo)過程解析
以上面的示例代碼為例,看一下游標(biāo)的詳細(xì)執(zhí)行過程。
游標(biāo)中有個指針,當(dāng)打開游標(biāo)的時候,才會執(zhí)行游標(biāo)對應(yīng)的 select 語句,這個指針會指向select 結(jié)果中第一行記錄。
當(dāng)調(diào)用 fetch 游標(biāo)名稱時,會獲取當(dāng)前行的數(shù)據(jù),如果當(dāng)前行無數(shù)據(jù),會觸發(fā) NOT FOUND 異常,當(dāng)觸發(fā) NOT FOUND 異常的時候,我們可以使用一個變量來標(biāo)記一下,如下代碼:
DECLARE CONTINUE HANDLER FOR NOT FOUND SET v_done=TRUE;
當(dāng)游標(biāo)無數(shù)據(jù)觸發(fā) NOT FOUND 異常的時候,將變量 v_down 的值置為 TURE ,循環(huán)中就可以通過 v_down 的值控制循環(huán)的退出。
如果當(dāng)前行有數(shù)據(jù),則將當(dāng)前行數(shù)據(jù)存到對應(yīng)的變量中,并將游標(biāo)指針指向下一行數(shù)據(jù),如下語句:
fetch 游標(biāo)名稱 into 變量列表;
到此這篇關(guān)于MySQL游標(biāo)的介紹與使用的文章就介紹到這了,更多相關(guān)MySQL游標(biāo)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MySQL實(shí)現(xiàn)批量插入測試數(shù)據(jù)的方式總結(jié)
在開發(fā)過程中經(jīng)常需要一些測試數(shù)據(jù),?這個時候如果手敲的話,?十行二十行還好,?多了就很死亡了,?接下來介紹兩種常用的MySQL測試數(shù)據(jù)批量生成方式,希望對大家有所幫助2023-05-05在Linux系統(tǒng)的命令行中為MySQL創(chuàng)建用戶的方法
這篇文章主要介紹了在Linux系統(tǒng)的命令行中為MySQL創(chuàng)建用戶的方法,包括對所建用戶的權(quán)限管理,需要的朋友可以參考下2015-06-06SQL實(shí)現(xiàn)Excel的10個常用功能的示例詳解
SQL,數(shù)據(jù)分析崗的必備技能,你可以不懂Python,R,不懂可視化,不懂機(jī)器學(xué)習(xí)。但SQL,你必須懂。本文為大家總結(jié)了SQL實(shí)現(xiàn)Excel的10個常用功能的示例代碼,感興趣的可以了解一下2022-07-07mysql中mydumper 和 mysqldump 對比使用
MySQL數(shù)據(jù)庫備份工具有其自帶的mysqldump,屬于mysql官方的一款備份工具。但是第三方備份工具mydumper憑借優(yōu)越的特點(diǎn)為更多人所使用。下面就通過測試驗(yàn)證它們之間的備份效率。2017-05-05SQL數(shù)據(jù)去重的3種方法實(shí)例詳解
SQL去重是數(shù)據(jù)分析工作中比較常見的一個場景,下面這篇文章主要給大家介紹了關(guān)于SQL數(shù)據(jù)去重的3種方法,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-01-01mysql不同數(shù)據(jù)庫不同數(shù)據(jù)表導(dǎo)入數(shù)據(jù)
這篇文章主要介紹了mysql不同數(shù)據(jù)庫不同數(shù)據(jù)表導(dǎo)入數(shù)據(jù)的相關(guān)資料,需要的朋友可以參考下2015-07-07