MySQL(8)---游標


Mysql(8)—游標

上一遍博客寫了有關存儲過程的語法知識 Mysql(7)---存儲過程
游標或許你在工作中很少用到,但用不到不代表不去了解它,但你真正需要它來解決問題的時候,再花時間去學習很可能會影響你的工作進度。
注意:MySQL游標只能用於存儲過程(和函數)。游標主要用於交互式應用。

一、概述

1、定義

游標是一個存儲在MySQL服務器上的數據庫查詢,它不是一條select語句,而是被該語句所檢索出來的結果集。

接下來會對這句話做出進一步解釋。

2、游標的作用

比如有這么個語句

SELECT name,age from person where age>10;

這個語句返回的很可能是多條語句,那么我如何遍歷每一條數據呢,這個時候就需要游標,游標可以理解成java的List<Object>集合,存儲了每一個含有"name"和"age"的對象。接下來我們就可以遍歷集合中每一個對象獲取"name"和"age"。

3、使用游標

使用游標可以大致分為這么幾步

聲明游標 :這個過程實際上是沒有遍歷數據的,它只是定義要使用的select語句來獲取數據。

打開游標 : 上面定義好后,那么這里就需要打開游標。這個過程用前面定義的select語句把數據實際檢索出來。即這個步驟之后,我們就可以遍歷游標中的數據了。

遍歷數據 : 對於有數據的游標,根據需要取出各行的數據來進行一定的操作。

關閉游標 : 使用完游標后,一定要關閉游標。

4、游標語法

**1)聲明游標 **

DECLARE cursor_name CURSOR FOR select_statement

這個語句聲明一個游標。也可以在子程序中定義多個游標,但是一個塊中的每一個游標必須有唯一的名字。聲明游標后也是單條操作的,但是SELECT語句不能有INTO子句。

2) 打開游標

OPEN cursor_name ;

這個語句打開先前聲明的游標。

3) 遍歷數據

FETCH cursor_name INTO var_name ;

這個語句用指定的打開游標讀取下一行(如果有下一行的話),並且前進游標指針。

4) 關閉游標

CLOSE cursor_name ;

下面會用一個詳細的例子來說明,通過這個例子就能很明白游標是什么了。


二、舉例

例子所需表

CREATE TABLE IF NOT EXISTS `store` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) NOT NULL,
  `count` int(11) NOT NULL DEFAULT '1',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=7;
 
INSERT INTO `store` (`id`, `name`, `count`) VALUES
(1, 'android', 15),
(2, 'iphone', 14),
(3, 'iphone', 20),
(4, 'android', 5),
(5, 'android', 13),
(6, 'iphone', 13);

1、例一

目的:我們現在要用存儲過程做一個功能,統計iphone的總庫存是多少,並把總數輸出到控制台。

delimiter $ # 申明結束標志
drop procedure if exists StatisticStore$ # 如果存儲過程已經存在則刪除
CREATE PROCEDURE StatisticStore()
BEGIN
	# 創建接收游標數據的變量
	declare c int;  # 獲取單條紀錄的數量
	declare n varchar(20); #獲取名稱
	# 創建總數變量
	declare total int default 0;
	# 創建結束標志變量
	declare done int default false;
	# 創建游標 獲取name和count的集合
	declare cur cursor for select name,count from store where name = 'iphone';
	# 指定游標循環結束時的返回值
	declare continue HANDLER for not found set done = true;
	# 設置初始值
	set total = 0;
	# 打開游標
	open cur;
	# 開始循環游標里的數據
	read_loop:loop
	# 根據游標當前指向的一條數據 插入到上面申明的局部變量中
	fetch cur into n,c;
	# 判斷游標的循環是否結束
	if done then
		leave read_loop;	# 跳出游標循環
	end if;
	# 獲取一條數據時,將count值進行累加操作,這里可以做任意你想做的操作,
	set total = total + c;
	# 有loop 就一定要有end loop
	end loop;
	# 關閉游標
	close cur; 
	# 輸出結果
	select total;
END $
# 調用存儲過程
call StatisticStore()$

看輸出結果 完美

在啰嗦幾句

fetch:是獲取游標當前指向的數據行,並將指針指向下一行,當游標已經指向最后一行時繼續執行會造成游標溢出。
使用loop循環游標時,他本身是不會監控是否到最后一條數據了,像下面代碼這種寫法,就會造成死循環;

read_loop:loop
fetch cur into n,c;
set total = total+c;
end loop;

在MySql中,造成游標溢出時會引發mysql預定義的NOT FOUND錯誤,所以在上面使用下面的代碼指定了當引發not found錯誤時定義一個continue 的事件,指定這個事件發生時修改done變量的值。

declare continue HANDLER for not found set done = true;

所以在循環時加上了下面這句代碼:

#判斷游標的循環是否結束
if done then
	leave read_loop;	#跳出游標循環
end if;

如果done的值是true,就結束循環。繼續執行下面的代碼。

2、游標嵌套例子

delimiter $ # 申明結束標志
drop procedure if exists StatisticStore3$
CREATE PROCEDURE StatisticStore3()
BEGIN
	declare _n varchar(20);
	declare done int default false;
	declare cur cursor for select name from store group by name; #其實就是獲得了兩個名稱的集合[android,iphone]
	declare continue HANDLER for not found set done = true;
	open cur;
	read_loop:loop
	fetch cur into _n;
	if done then
		leave read_loop;
	end if;
	begin
		declare c int;
		declare n varchar(20);
		declare total int default 0;
		declare done1 int default false;
		declare cur cursor for select name,count from store where name = _n; 
		declare continue HANDLER for not found set done1 = true;
		set total = 0;
		open cur; # 這里游標名稱和上面重復了,mysql默認就近原則 所以遍歷的是最近的那么 但還是非常不建議取一樣的名稱
		iphone_loop:loop
		fetch cur into n,c;
		if done1 then
			leave iphone_loop;
		end if;
		set total = total + c;
		end loop;
		close cur;
		select _n,n,total; # select 只輸出一次,而且是第一次遍歷數據
	end;
	end loop;
	close cur;
END$
call StatisticStore3()$

執行結果(select 只輸出一次,而且是第一次遍歷數據)

參考

1、mysql cursor概念

2、MySql中游標舉例



只要自己變優秀了,其他的事情才會跟着好起來(少將10)


免責聲明!

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



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