《MySQL必知必會》第24章 有bug

2021-10-03 07:10:54 字數 4430 閱讀 4746

有時候,需要在檢索出來的行中前進或後退一行或多行,這就是游標,游標是乙個儲存在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,...