已知MySQL檢索操作返回一組稱為結果集的行。這組返回的行都是與SQL語句相匹配的行(零行或者多行)。使用簡單的SQL語句,例如,沒有辦法得到第一行、下一行或前10行,也不存在每次一行地處理所有行的簡單辦法(相對於成批的處理它們)。
有時,需要在檢索出來的行中前進或者后退一行或者多行,這就是使用游標的原因,游標(cursor)是一個存儲在MySQL服務器上的數據庫查詢。它不是一條SQL語句,而是被SQL語句檢索出來的結果集。在存儲了游標只有,用戶可以根據需要滾動或瀏覽其中的數據。
游標主要用於交互式應用,其中用戶需要滾動屏幕中的數據,並對數據進行瀏覽或者作出更改。
不像多數DBMS,MySQL游標只能用於存儲過程(和函數)。
使用游標:
使用游標明確的幾個步驟:
1.在能夠使用游標前,必須聲明(定義)它。這個過程實際上沒有檢索數據,它只是要定義要使用的SELECT語句。
2.一旦聲明后,鼻血打開游標以供使用。這個過程用前面定義的SELECT語句把數據實際檢索出來。
3.對於填有數據的游標,根據需要取出(檢索)各行。
4.在結束游標使用時,必須關閉游標。
在聲明游標后,可以根據需要頻繁地打開或者關閉游標。在游標打開后,可根據需要頻繁地執行取操作。
創建游標:
游標用DECLARE語句創建。DECLARE命名游標,並定義相應的SELECT語句,根據需要帶WHERE和其它子句。例如,下面的語句定義了名為ordernumbers的游標,使用了可以檢索的所有訂單的SELECT語句。
CREATE PROCEDURE processorders() BEGIN DECLARE ordernumbers CURSOR FOR SELECT order_num FORM orders; END;
這個存儲過程並沒有做很多事情,DECLARE語句用來定義和命名游標,這里為ordernumbers。存儲過程處理完成后,游標就消失(因為它局限於存儲過程)。
在定義游標之后,可以打開它。
打開和關閉游標:
打開游標:OPEN ordernumbers;在處理OPEN語句時執行查詢,存儲檢索出的數據以供瀏覽和滾動。
關閉游標:CLOSE ordernumbers;CLOSE釋放游標使用的所有內部內存和資源,因此在每個游標不再需要時都應該關閉。
隱含關閉:如果不明確關閉游標,MySQL將會在到達END語句時自動關閉它。
下面是前面例子的修改版本:
CREATE PROCEDURE processorders() BEGIN --Declare the cursor DECLARE ordernumbers CURSOR FOR SELECT order_num FROM orders; --Open the cursor OPEN ordernumbers; --Close the cursor CLOSE ordernumbers; END;
使用游標數據:
在一個游標被打開后,可以使用FETCH語句分別訪問它的每一行。FETCH指定檢索的數據(所需的列),檢索出來的數據存儲在什么地方。它還向前移動游標中的內部行指針,下一條FETCH語句檢索下一行(不重復讀取每一行)。
例子:從游標中檢索單個行(第一行):
CREATE PROCEDURE processorders() BEGIN --Declare local variables; DECLARE o INT; --Declare the cursor DECLARE ordernumbers CURSOR FOR SELECT order_num FROM orders; --Open the cursor OPEN ordernumbers; --Get order number FETCH ordernumbers INTO o;--用來檢索當前行的order_num列(將自動從第一行開始)到一個名為o的局部聲明的變量中。對檢索出的數據不做任何處理。 --Close the cursor CLOSE ordernumbers; END;
例子:循環檢索數據,從第一行到最后一行。
CREATE PROCEDURE processorders() BEGIN --Declare local variables; DECLARE done BOOLEAN DEFAULT 0; DECLARE o INT; --Declare the cursor DECLARE ordernumbers CURSOR FOR SELECT order_num FROM orders; --Declare continue handler DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done=1; --Open the cursor OPEN ordernumbers; --Loop through all rows REPEAT --Get order number FETCH ordernumbers INTO o; -End of loop UNTIL done END REPEAT; --Get order number FETCH ordernumbers INTO o;--用來檢索當前行的order_num列(將自動從第一行開始)到一個名為o的局部聲明的變量中。對檢索出的數據不做任何處理。 --Close the cursor CLOSE ordernumbers; END;
與前一個例子一樣,這個例子使用FETCH檢索當前order_num到聲明的名為o的變量中。但是與前一個例子不一樣的是,這個例子中的FETCH是在REPEAT內,因此它反復執行到done為真(由UNTIL done END REPEAT;規定)。為使它起作用,用一個DEFAULT 0(假,不結束)定義變量done。那么,done怎樣才能在結束時被設置為真呢?答案是以下語句:
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done=1;
這條語句定義了一個CONTINUE HANDLER,它是在條件出現時被執行的代碼。這里,它支出當SQLSTATE‘02000’出現時,SET done=1。SQLSTATE'02000'是一個未找到條件,當REPEAT由於沒有更多的行功勛換而不能繼續時,出現這個條件。
MySQL錯誤代碼列表:請參閱http://dev.mysql.com/doc/mysql/en/error-handling.html
DECLARE語句的次序,DECALRE語句的發布存在特定的次序。用DECLARE語句定義的局部變量必須在定義任意游標或句柄之前定義,而句柄必須在游標之后定義。不遵守詞順序將產生錯誤消息。
如果調用這個存儲過程,它將定義幾個變量和一個CONTINUE HANDLER,定義並打開一個游標,重復讀取所有行,然后關閉游標。
重復或循環:
除這里使用的REPEAT外,MySQL還支持循環語句,它可以用來重復執行代碼,直到使用LEAVE語句手動退出為止。通常REPEAT語句得語法使它更適合於對游標進行循環。
為了把這些內容組織起來,下面對游標存儲過樣例更進一步的修改,這次對取出的數據進行某種實際的處理。
CREATE PROCEDURE processorders() BEGIN --Declare local variables; DECLARE done BOOLEAN DEFAULT 0; DECLARE o INT; DECLARE t DECIMAL(8,2); --Declare the cursor DECLARE ordernumbers CURSOR FOR SELECT order_num FROM orders; --Declare continue handler DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done=1; --Create table to store the results CREATE TABLE IF NOT EXISTS ordertotals (order_num INT,total DECIMAL(8,2)); --Open the cursor OPEN ordernumbers;--打開游標 --Loop through all rows REPEAT --Get order number FETCH ordernumbers INTO o; --Get the total for this order CALL ordertotal(o,1,t);--調用某一存儲過程,並傳遞三個參數; --Insert order and total into ordertotals INSERT INTO ordertotals(order_num,totals) VALUES(o,t); -End of loop UNTIL done END REPEAT; --Get order number FETCH ordernumbers INTO o;--用來檢索當前行的order_num列(將自動從第一行開始)到一個名為o的局部聲明的變量中。對檢索出的數據不做任何處理。 --Close the cursor CLOSE ordernumbers;--關閉游標 END;
此存儲過程不返回數據,但它可以創建並填充另一個表,可以用一條簡單的SELECT語句查看該表;
SELECT * FROM ordertotals;
這樣,我們就得到了存儲過程、游標、逐行處理以及存儲過程調用其他存儲過程的一個完整的工作示例。