1. 程式人生 > >《MySQL必知必會》學習筆記十四(遊標)------瞭解部分

《MySQL必知必會》學習筆記十四(遊標)------瞭解部分

MySQL必知必會知識預覽
第一章——瞭解SQL
第二章——MySQL簡介
第三章——使用MySQL
第四章——檢索資料
第五章——排序檢索資料
第六章——過濾資料
第七章——資料過濾
第八章——用萬用字元進行過濾
第九章——用正則表示式進行搜尋
第十章——建立計算欄位
第十一章——使用資料處理函式
第十二章——彙總資料
第十三章——分組資料
第十四章——使用子查詢
第十五章——聯結表
第十六章——建立高階聯結
第十七章——組合查詢
第十八章——全文字搜尋
第十九章——插入資料
第二十章——更新和刪除資料
第二十一章——建立和操縱表
第二十二章——使用檢視
第二十三章——使用儲存過程
第二十四章——使用遊標
第二十五章——使用觸發器
第二十六章——管理事務處理
第二十七章——全球化和本地化
第二十八章——安全管理
第二十九章——資料庫維護
第三十章——改善效能
————————————– 華麗的分隔符 ————————————————–

遊標

為什麼使用遊標,什麼是遊標,如何使用遊標,

————————————– ————————————– ————————————–

遊標的概念

首先考慮:MySQL檢索操作返回一組稱為結果集的行。這組返回的行都是與SQL語句相匹配的行(零行或多行)。使用簡單的SELECT語句,沒有辦法得到第一行、下一行或前十行等,也不存在每次一行地處理所有航的簡單方法(相對於成批的處理他們)。
有時候,我們需要在檢索出來的行中前進或者後退一行或者多行。這就是我們為什麼使用遊標。

於是:

遊標是一個儲存在MySQL伺服器上的資料庫查詢呢,她不是一條SELECT語句,而是被該語句檢索出來的結果集。

在儲存了遊標之後,應用程式可以根據需要進行滾動或者瀏覽其中的資料。

遊標主要是用於互動式應用,其中使用者需要滾動螢幕上的資料,並對資料進行瀏覽或做出更改。

注意:遊標只能用於儲存過程。(僅限MySQL)。

使用遊標規則

1)在能夠使用遊標錢,必須宣告(定義)它。這個過程實際上沒有檢索資料,他只是定義要使用的SELECT語句。

2)一旦聲明後,必須開啟遊標以供使用,這個過程用前面定義的SELECT語句把資料實際檢索出來。

3)對於填有資料的遊標,根據需要取出(檢索)各行。

4)在結束遊標使用時,必須關閉遊標。

在宣告遊標後,可根據需要頻繁地開啟和關閉遊標。再開啟遊標之後,可以根據需要頻繁地執行取操作。

使用遊標

1、建立遊標

遊標用DECLARE語句建立。DECLARE命名遊標,並定義相關的SELECT語句,根據需要帶WHERE和其他子句。

CREATE PROCEDURE processorders()

BEGIN 
    DECLARE ordernumbers CURSOR
    FOR
        SELECT order_num FROM orders;
END;        

定義了名為 ordernumber 的遊標,使用了可以檢索所有訂單的SELECT語句。

DECLARE 語句用來完成定義和命名遊標。需要注意的是在儲存過程處理完成後,遊標就消失。【遊標僅僅侷限於儲存過程】

2、開啟和關閉遊標

開啟或者關閉遊標使用OPEN CursorName和CLOSE CursorName

OPEN ordernumbers;
close ordernumbers;

在處理OPEN語句時執行查詢,儲存檢索出的資料以供瀏覽和滾動。
CLOSE釋放遊標使用的所有內部記憶體和資源,因此每個遊標不再需要時都應該關閉。
在一個遊標關閉後,沒有再次重新開啟,則不能使用它。但是使用宣告過的遊標不需要再次宣告,用OPEN語句開啟它就可以了。
隱含關閉:如果你不明確關閉遊標,則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;

    //儲存過程宣告、開啟和關閉一個遊標,對資料未做處理  

3、使用遊標資料

FETCH 語句
在開啟遊標之後,可以使用FETCH語句分別訪問它的每一行。
FECTCH 指定檢索什麼資料(所需要的列),檢索出來的資料儲存在什麼地方。它還向前移動遊標中的內部行指標,使下一條FETCH語句檢索下一行(不重複讀取同一行)

1、從遊標中檢索單個行(第一行)

CREATE PROCEDURE processorders()
    BEGIN
        -- declare local variables
        DECLARE o INT;
        --delcare the cursor
        DECLARE ordernumbers CURSOR
            FOR  
            SELECT order_num FROM orders;

        -- Open the cursor
        OPEN  ordernumbers;
        -- Get order number
        FETCH ordernumbers INTO o;
        -- Close the cursor
        CLOSE ordernumbers;

    END;

FETCH 用來檢索當前行的order_num列(自動從第一行開始)到一個名為o的區域性變數中。對檢索資料不做任何處理。

2、迴圈檢索資料,從第一行到最後一行

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;
        -- close the cursor
        CLOSE ordernumbers;

    END;

使用FETCH檢索當前order_num到宣告的名為o的變數中,REPEAT將FETCH包含在內,反覆執行,直到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由於沒有更多的行供迴圈而不能繼續時,出現這個條件

DECLARE 語句的次序 DECLARE 語句的釋出在特定的次序。用DECLARE語句定義的區域性變數必須在定義任意遊標或者控制代碼之前定義,而控制代碼必須在遊標之後定義,不遵守這樣的順序,將會產生錯誤訊息。

如果我們呼叫這個儲存過程,它將定義幾個變數和一個CONTINUE HANDLER,定義並開啟一個遊標,重複讀取所有行,然後關閉遊標。我們可以在迴圈內放入任意需要的處理(在FETCH語句之後,迴圈結束之前)
在這裡我們使用了REPEAT語句進行迴圈,另外MySQL還支援迴圈語句【三種方式while、repeat、loop】,他可以重複執行程式碼。通常REPEAT語句的語法更適合用於對遊標的迴圈。

3、對資料進行操作

        CREATE PROCEDURE processorders()
            BEGIN
                -- Declare local variables
                DECLARE done BOOLEAN DEFAULT 0;
                DECLARE o INT;
                DECLATE 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 a table to store the results
                CREATE TABLE IF NOT EXISTS ordertotals(order_num INT, total DECLMAL(8,2)); 
                --Open the cursor
                OPEN ordernumbers;
                --Loop through all rows
                REPEAT
                --Get order number
                FETCH ordernumbers INTO o;
                -- Get order number FETCH ordernumbers INTO o;
                -- get the total foe this order
                CALL ordertotal(o,1,t);
                --Inert order and total into ordertotals
                INSERT INTO ordertotas(order_num,total)VALUES (o,t);
                -- END of loop
                UNTIL done END REPEAT;
                -- close the cursor
                CLOSE ordernumbers;
            END;
-------------------------------------------
ordertotal //帶稅合計儲存過程【學習筆記十三】 

-- Name:ordertotal
-- Parameters: onumber = order number
--              taxable = 0 if not taxable,1 if taxable
--              ototal = order total variable



CREATE PROCEDURE ordertotal(
 IN onumber INT,
 IN taxable BOOLEAN,
 OUT ototal DECIMAL(8,2)
 )COMMENT 'Obtain order total, optionally adding tax'
 BEGIN
  -- declear variable for total
  DECLARE total DECIMAL(8,2);
  -- declear tax percentage
  DECLARE taxrate INT DEFAULT 6;
  -- get the order total
    SELECT Sum(item_price * quantity) FROM orderitems WHERE order_num = onumber INTO total;

-- IS this taxable?

IF taxable THEN 
   -- yes ,so add taxrate to the total
   SELECT total+(total/100*taxrate)INTO total;
   END IF;
 -- finally ,save to out variable
 SELECT total INTO ototal;
END;

我們在這裡增加了一個名為t的變數(儲存每個訂單的合計)。此儲存過程還在執行中建立了一個新表(不存在的情況下進行建立),名為ordertotals。這個表將儲存儲存過程生成的結果。FETCH獲取每個order_num ,然後用CALL執行另外一個儲存過程來計算滅個訂單的帶稅的合計儲存到t中,最後我們利用INSERT儲存每個訂單的訂單號和合計。

這個儲存過程不返回資料,但是它建立和填充另外一個表,可以使用一條簡單的【SELECT * from ordertotals】進行查詢。
從前到後,我們得到了儲存過程、遊標、逐行處理以及儲存過程呼叫其他儲存過程的一個完整的工作例子。

————————————– ————————————– ————————————–
個人認為遊標並不是重要部分是因為,我們在獲取資料的時候總是會獲取所有資料,然後在後臺程式碼中根據需求進行分析,一般不會在資料庫中進行前一個後一個等等類似的資料操作。即使在分頁過程中會運用到前資料或者後資料,那樣的話我們直接是利用LIMIT進行 操作,而用不到遊標,而且遊標必須是限制在儲存過程中,所以,我認為了解即可。