有時候,需要在檢索出來的行中前進或後退一行或多行,這就是游標,游標是乙個儲存在mysql伺服器上的資料庫查詢,不是一條select語句,而是被該語句檢索出來的結果集
游標主要用於互動式應用,使用者可以滾動螢幕上的資料進行瀏覽或更改
mysql游標只能用於儲存過程(和函式)
使用步驟為
1、宣告(定義)游標
2、開啟游標,這個過程就是把資料實際檢索出來
3、根據需要取出檢索出來的各行
4、關閉游標
建立、開啟和和關閉游標
create
procedure processorders(
)begin
-- 定義游標
declare ordernumbers cursor
forselect order_num from orders;
-- 開啟游標
open ordernumbers;
-- 關閉游標
close ordernumbers;
end;
要注意open ***,close ***語句應當在儲存過程內(begin …end之間)使用,單獨使用會報錯
使用fetch分別訪問每一行,會向前移動游標中的內部行指標,使下一條fetch語句檢索下一行,保證不重複讀取
create
procedure processorders(
)begin
--定義乙個區域性變數
declare o int
;declare ordernumbers cursor
forselect order_num from orders;
open ordernumbers;
--檢索第一行
fetch ordernumbers into o;
close ordernumbers;
end;
將檢索出的第一行儲存到區域性變數o中,但不做處理
迴圈檢索資料,從第一行到最後一行
create
procedure processorders(
)begin
--定義區域性變數,必須在定義游標之前定義
declare done boolean
default0;
declare o int
;declare ordernumbers cursor
forselect order_num from orders;
declare
continue
handler
for sqlstate '02000'
set done=1;
open ordernumbers;
--迴圈每一行
repeat
fetch ordernumbers into o;
until done end
repeat
;close ordernumbers;
end;
本例中的fetch反覆執行直到done為真,所以一開始用default 0定義done,至於done何時為真
declare
continue
handler
for sqlstate '02000'
set done=
1;
該語句定義了乙個continue handler,當sqlstate '02000』出現時,set done=1,sqlstate '02000』是乙個未找到條件,當repeat由於沒有更多的行供迴圈而不能繼續時出現該條件
對取出的資料進行處理
-- 上一章學習過的儲存過程,待會要用到
create
procedure ordertotal(
in onumber int
,in taxable boolean
,out ototal decimal(8
,2))
comment
'obtain order total, optionally adding tax'
begin
declare total decimal(8
,2);
declare taxrate int
default6;
select
sum(item_price*quantity)
from orderitems
where order_num = onumber
into total;
if taxable then
select total+
(total/
100*taxrate)
into total;
endif
;select total into ototal;
end;
-- 如果已經存在該過程,先刪除
drop
procedure
ifexists processorders;
create
procedure processorders(
)begin
-- declare local variables
declare done boolean
default0;
declare o int
;declare t decimal(8
,2);
-- declare the cursor
declare ordernumbers cursor
forselect order_num from orders;
-- declare continue handler
declare
continue
handler
for sqlstate '02000'
set done =1;
-- 如果表已經存在,先刪除
drop
table
ifexists ordertotals;
-- 建立表
create
table
ifnot
exists ordertotals (order_num int
, total decimal(8
,2))
;-- open the cursor
open ordernumbers;
-- loop through all rows
repeat
-- 取第一行
fetch ordernumbers into o;
-- done仍為0
ifnot done then
-- 呼叫儲存過程,將結果賦值給t
call ordertotal(o,
1, t)
;-- 插入一行到新建的表中
insert
into ordertotals(order_num, total)
values
(o, t)
;endif;
-- end of loop
until done end
repeat
;-- close the cursor
close ordernumbers;
end;
-- create只相當於宣告乙個過程,call是呼叫,若沒有該語句而執行接下來的select語句,報錯:表不存在
call processorders;
-- 檢視該錶
select
*from ordertotals;
我們增加變數t,用於儲存每個訂單的帶稅的合計,ordertotals表儲存產生的結果
這裡的**與書本中的**不同,書中的**有bug,導致結果的最後一行輸出兩次,先看有bug的**
repeat
fetch ordernumbers into o;
call ordertotal(o,
1, t)
;insert
into ordertotals(order_num, total)
values
(o, t);
until done end
repeat
;
大概原因如下,在檢索完最後一行後,回到迴圈的最開始,mysql嘗試fetch新的一行,但此時已經沒有多的行可以檢索,此時done變為1,理論上此時應報錯結束迴圈,但mysql並不如此,而是繼續進行此次迴圈,而o,t的值為上一輪迴圈的值,從而導致表中最後會有重複的兩行,由於此次迴圈後done為1,因此退出迴圈,這也就是為什麼自己的**的迴圈體中要多一次判斷,當done為1時就不再執行接下來的操作
具體解釋以及補充
《MYSQL必知必會》第1 9章
資料庫基礎 資料庫 儲存有組織的資料的容器 表 某種特定型別資料的結構化清單 列 表中的乙個字段資料型別 所容許的資料的型別 行 表中的乙個記錄 主鍵 一列,其值能夠唯一區分表中每個行 sql是結構化查詢語言 structured query language 的縮寫 mysql 簡介 mysql是...
mysql必知必會 mysql必知必會(四)
十四 理解子查詢 1 通過子查詢過濾 這本書在所有的章節都關連到了資料庫表,訂單資料是儲存在兩個表中,orders表儲存著 訂單號碼 顧客id和訂單日期。個人的訂單列表關連著orderitems表,訂單表沒有儲存顧客資訊,它只是儲存著顧客id,這實際的顧客資訊是儲存在customers表中。現在假設...
MySQL必知必會 第15章 連線表
連線表的關鍵在於 1 規定要連線起來的所有表 2 表之間如何關聯。student表如下所示 scoretable如下所示 1.通過兩個表的id number欄位將兩個表連線起來 select student.id,student.name,scoretable.score from student,...