本文目錄:1.游標說明2.使用游標3.游標使用示例 1.游標說明 游標,有些地方也稱為游標。它的作用是在一個結果集中逐條逐條地獲取記錄行並操作它們。 例如: 其中select是游標所操作的結果集,游標每次fetch一行中的name和age欄位,並將每一行的這兩個欄位賦值給變數var1和var2。 有 ...
1.游標說明
游標,有些地方也稱為游標。它的作用是在一個結果集中逐條逐條地獲取記錄行並操作它們。
例如:
其中select是游標所操作的結果集,游標每次fetch一行中的name和age欄位,並將每一行的這兩個欄位賦值給變數var1和var2。
有很多、很多、很多人,很多、很多、很多書都強烈建議:能不用游標儘量不要用游標。因為它違背了集合的理論,集合取數據是一把一把抓,游標取數據的時候一行一行取,每取一行操作一行,而且在每一行上都有額外的資源消耗。總之,游標效率低、資源消耗高。
其實很多領域都有這樣的優化:把數據先集中起來,集中到了一定量再一次性處理,這樣的處理方式效率要高得多。比如寫日誌到磁碟上,可以每產生一條日誌就刷入磁碟,也可以先產生一堆日誌緩存起來,之後一次性刷如磁碟。後者效率要高得多。
集合取數據的時候關註點在於想要什麼數據,而不關註怎麼去獲取數據,游標的關註點則在於怎麼獲取這些數據:將游標指針作為遍歷依據,遍歷到哪行數據就返回這行數據然後停下來處理數據,再繼續遍曆數據。習慣於迭代的人比較喜歡游標,特別是習慣C語言的人,因為游標就是遍曆數據行的行為。
在MySQL、MariaDB中實現的游標比較簡單,它只有一種遍歷方式:逐行向前遍歷。MariaDB 10.3後,游標方面支持的更完整一點:支持游標參數。
游標的使用包括聲明游標、打開游標、使用游標和關閉游標(MySQL/MariaDB中的游標無需釋放)。游標必須聲明在處理程式之前,並且在聲明保存結果集的變數之後。另外,游標是一種複合語句結構(就像begin...end),只能用於stored procedure或stored function中。
2.使用游標
1.聲明游標
DECLARE cursor_name CURSOR FOR select_statement;
其中select_statement是游標需要從中獲取的結果集。
例如:
declare cur_city cursor for select id,'name',population from world,city;
在MariaDB 10.3中,支持游標參數,該參數可以傳遞到select_statement中:
DECLARE cursor_name CURSOR(param1 data_type,param2 data_type2...) FOR select_statement;
例如:
declare cur_stu cursor(min int,max int) for select id,name from Student where id between min and max;
註意,mariaDB 10.3之前的語法也能在10.3版本上執行,因為之前的語法是10.3版本中不帶參數的特殊情況。
2.聲明處理程式
一般來說,游標是用在逐條取結果集的情況下,所以在使用游標的時候基本都會放在迴圈結構中迴圈獲取數據存儲到變數中。但如何在取完數據後退出迴圈?
在游標無法獲取到下一行數據的時候,將會返回一個1329錯誤碼,這個錯誤碼對應的SQL狀態碼為"02000",它們等價於NOT FOUND(這幾個是等價的,只是MariaDB中分了3類描述問題的代碼而已)。這時可以在聲明游標後定義一個handler,用於處理NOT FOUND。
例如下麵是適合游標NOT FOUND時的CONTINUE處理器,表示當找不到下一行數據時繼續執行後面的程式:
DECLARE CONTINUE HANDLER FOR NOT FOUND statement;
對於處理游標的HANDLER,通常statement部分是SET語句,用於設置一些變數。例如:
declare continue handler for not found set var_name=value;
這時,當取不到下一條記錄時即已經取完記錄時,就設置變數var_name=value。之後就可以通過該變數的值作為退出迴圈的條件。
關於handler詳細內容,見我翻譯的MariaDB手冊:https://mariadb.com/kb/zh-cn/declare-handler/
3.打開游標
當聲明瞭一個游標後,必須要打開游標才能使用游標。
open cursor_name;
例如:
open cur_city;
對於mariadb 10.3,由於支持游標參數,因此語法為:
open cursor_name(value1,value2);
例如:
open cur_stu(4,10);
4.使用游標(fetch into)
通過fetch into命令將每次fetch到的結果存儲到預先定義好的變數中。註意,這個變數必須是本地變數(局部變數),不能是用戶自定義變數,且這個變數必須定義在游標聲明語句之前。
fetch cursor_name into var_name;
例如:
fetch cur_city into city_id,city_name,city_popcnt;
在上面已經說過了,一般游標都會在迴圈結構中使用。以下是在repeat結構中使用游標;
repeat
fetch ... into ...
until var_name=value
end repeat;
5.關閉游標
close cursor_name;
例如:
close cur_city;
3.游標使用示例
以下是MariaDB 10.3版本之前(也適用於10.3)的游標使用示例:將表t1和表t2中每行中的某一列作比較,將較大值插入到表t3中。
create or replace table t1(i int);
create or replace table t2(i int);
create or replace table t3(i int);
insert into t1 values(5),(10),(20);
insert into t2 values(15),(30),(10);
delimiter $$
create or replace procedure proc1()
begin
declare done int default false; /* 用於判斷退出迴圈 */
declare x,y int; /* 用於保存fetch結果 */
declare cur1 cursor for select i from t1; /* fetch t1的游標 */
declare cur2 cursor for select i from t2; /* fetch t2的游標 */
declare continue handler for not found set done=true; /* not found時,退出迴圈 */
open cur1;
open cur2;
my_loop: LOOP
fetch cur1 into x;
fetch cur2 into y;
if done then
leave my_loop;
end if;
if x <= y then
insert into t3 values(y);
else
insert into t3 values(x);
end if;
end loop;
close cur1;
close cur2;
end$$
delimiter ;
call proc1;
查看表t3:
select * from t3;
+------+
| i |
+------+
| 15 |
| 30 |
| 20 |
+------+
下麵是MariaDB 10.3上使用游標的一個示例:將表t1中i欄位某一段數據插入到表t2中。
create or replace table t1(i int);
create or replace table t2(i int);
insert into t1 values(5),(10),(20),(30),(40);
delimiter $$
create or replace procedure proc1(min int,max int)
begin
declare done int default false;
declare x int;
declare cur1 cursor(cmin int,cmax int) for select i from t1 where t1.i between cmin and cmax;
declare continue handler for not found set done=true;
open cur1(min,max);
my_loop: LOOP
fetch cur1 into x;
if done then
leave my_loop;
end if;
insert into t2 values(x);
end loop;
close cur1;
end$$
delimiter ;
call proc1(10,40);
查看t2結果:
MariaDB [test]> select * from t2;
+------+
| i |
+------+
| 10 |
| 20 |
| 30 |
| 40 |
+------+
回到Linux系列文章大綱:http://www.cnblogs.com/f-ck-need-u/p/7048359.html
回到網站架構系列文章大綱:http://www.cnblogs.com/f-ck-need-u/p/7576137.html
回到資料庫系列文章大綱:http://www.cnblogs.com/f-ck-need-u/p/7586194.html
轉載請註明出處:http://www.cnblogs.com/f-ck-need-u/p/8722244.html
註:若您覺得這篇文章還不錯請點擊右下角推薦,您的支持能激發作者更大的寫作熱情,非常感謝!