MySQL存儲過程

摘自:https://www.cnblogs.com/l5580/p/5993238.htmlhtml

 

MySQL5 中添加了存儲過程的支持。mysql

    大多數SQL語句都是針對一個或多個表的單條語句。並不是全部的操做都怎麼簡單。常常會有一個完整的操做須要多條才能完成sql

    存儲過程簡單來講,就是爲之後的使用而保存的一條或多條MySQL語句的集合。可將其視爲批文件。雖然他們的做用不只限於批處理。數據庫

    爲何要使用存儲過程:優勢安全

        1 經過吧處理封裝在容易使用的單元中,簡化複雜的操做服務器

        2 因爲不要求反覆創建一系列處理步驟,這保證了數據的完整性。若是開發人員和應用程序都使用了同一存儲過程,則所使用的代碼是相同的。還有就是防止錯誤,須要執行的步驟越多,出錯的可能性越大。防止錯誤保證了數據的一致性。函數

        3 簡化對變更的管理。若是表名、列名或業務邏輯有變化。只須要更改存儲過程的代碼,使用它的人員不會改本身的代碼了都。性能

        4 提升性能,由於使用存儲過程比使用單條SQL語句要快命令行

        5 存在一些職能用在單個請求中的MySQL元素和特性,存儲過程可使用它們來編寫功能更強更靈活的代碼指針

        換句話說3個主要好處簡單、安全、高性能

    缺點

        1 通常來講,存儲過程的編寫要比基本的SQL語句複雜,編寫存儲過程須要更高的技能,更豐富的經驗。

        2 你可能沒有建立存儲過程的安全訪問權限。許多數據庫管理員限制存儲過程的建立,容許用戶使用存儲過程,但不容許建立存儲過程

    存儲過程是很是有用的,應該儘量的使用它們


 

    執行存儲過程

        MySQL稱存儲過程的執行爲調用,所以MySQL執行存儲過程的語句爲CALL        .CALL接受存儲過程的名字以及須要傳遞給它的任意參數

            CALL productpricing(@pricelow , @pricehigh , @priceaverage);

            //執行名爲productpricing的存儲過程,它計算並返回產品的最低、最高和平均價格


 

    建立存儲過程

        CREATE  PROCEDURE 存儲過程名()

           一個例子說明:一個返回產品平均價格的存儲過程以下代碼:

           CREATE  PROCEDURE  productpricing()

           BEGIN

            SELECT Avg(prod_price)  AS priceaverage

           FROM products;

           END;

        //建立存儲過程名爲productpricing,若是存儲過程須要接受參數,能夠在()中列舉出來。即便沒有參數後面仍然要跟()。BEGIN和END語句用來限定存儲過程體,過程體自己是個簡單的SELECT語句

        在MYSQL處理這段代碼時會建立一個新的存儲過程productpricing。沒有返回數據。由於這段代碼時建立而不是使用存儲過程。

 


 

    Mysql命令行客戶機的分隔符

        默認的MySQL語句分隔符爲分號 ; 。Mysql命令行實用程序也是 ; 做爲語句分隔符。若是命令行實用程序要解釋存儲過程自身的 ; 字符,則他們最終不會成爲存儲過程的成分,這會使存儲過程當中的SQL出現句法錯誤

        解決方法是臨時更改命令實用程序的語句分隔符

            DELIMITER //    //定義新的語句分隔符爲//

            CREATE PROCEDURE productpricing()

            BEGIN

            SELECT Avg(prod_price) AS priceaverage

            FROM products;

            END //

            DELIMITER ;    //改回原來的語句分隔符爲 ;

            除\符號外,任何字符均可以做爲語句分隔符

        CALL productpricing();  //使用productpricing存儲過程

        執行剛建立的存儲過程並顯示返回的結果。由於存儲過程其實是一種函數,因此存儲過程名後面要有()符號


 

    刪除存儲過程

        DROP PROCEDURE productpricing ;     //刪除存儲過程後面不須要跟(),只給出存儲過程名

        爲了刪除存儲過程不存在時刪除產生錯誤,能夠判斷僅存儲過程存在時刪除

        DROP PROCEDURE IF EXISTS

        使用參數

        Productpricing只是一個簡單的存儲過程,他簡單地顯示SELECT語句的結果。

        通常存儲過程並不顯示結果,而是把結果返回給你指定的變量

            CREATE PROCEDURE productpricing(

            OUT p1 DECIMAL(8,2),

            OUT ph DECIMAL(8,2),

            OUT pa DECIMAL(8,2),

            )

            BEGIN

            SELECT Min(prod_price)

            INTO p1

            FROM products;

            SELECT Max(prod_price)

            INTO ph

            FROM products;

            SELECT Avg(prod_price)

            INTO pa

            FROM products;

            END;

            此存儲過程接受3個參數,p1存儲產品最低價格,ph存儲產品最高價格,pa存儲產品平均價格。每一個參數必須指定類型,這裏使用十進制值。關鍵字OUT指出相應的參數用來從存儲過程傳給一個值(返回給調用者)。MySQL支持IN(傳遞給存儲過程)、OUT(從存儲過程當中傳出、如這裏所用)和INOUT(對存儲過程傳入和傳出)類型的參數。存儲過程的代碼位於BEGIN和END語句內,如前所見,它們是一些列SELECT語句,用來檢索值,而後保存到相應的變量(經過INTO關鍵字)

        調用修改過的存儲過程必須指定3個變量名:

        CALL productpricing(@pricelow , @pricehigh , @priceaverage);

        這條CALL語句給出3個參數,它們是存儲過程將保存結果的3個變量的名字

    變量名  全部的MySQL變量都必須以@開始

    使用變量

        SELECT @priceaverage ;

        SELECT @pricelow , @pricehigh , @priceaverage ;   //得到3給變量的值

        下面是另外一個例子,此次使用IN和OUT參數。ordertotal接受訂單號,並返回該訂單的合計

            CREATE PROCEDURE ordertotal(

           IN onumber INT,

           OUT ototal DECIMAL(8,2)

            )

            BEGIN

            SELECT Sum(item_price*quantity)

            FROM orderitems

            WHERE order_num = onumber

            INTO ototal;

            END;

            //onumber定義爲IN,由於訂單號時被傳入存儲過程,ototal定義爲OUT,由於要從存儲過程當中返回合計,SELECT語句使用這兩個參數,WHERE子句使用onumber選擇正確的行,INTO使用ototal存儲計算出來的合計

    爲了調用這個新的過程,可使用下列語句:

        CALL ordertotal(2005 , @total);   //這樣查詢其餘的訂單總計可直接改變訂單號便可

        SELECT @total;


 

   創建智能的存儲過程

        上面的存儲過程基本都是封裝MySQL簡單的SELECT語句,但存儲過程的威力在它包含業務邏輯和智能處理時才顯示出來

        例如:你須要和之前同樣的訂單合計,但須要對合計增長營業稅,不活只針對某些顧客(或許是你所在區的顧客)。那麼須要作下面的事情:

            1 得到合計(與之前同樣)

            2 吧營業稅有條件地添加到合計

            3 返回合計(帶或不帶稅)

        存儲過程的完整工做以下:

            -- Name: ordertotal

            -- Parameters: onumber = 訂單號

            --           taxable = 1爲有營業稅 0 爲沒有

            --           ototal = 合計

            CREATE  PROCEDURE ordertotal(

            IN onumber INT,

            IN taxable BOOLEAN,

            OUT ototal DECIMAL(8,2)

            -- COMMENT()中的內容將在SHOW PROCEDURE STATUS ordertotal()中顯示,其備註做用

            ) COMMENT 'Obtain order total , optionally adding tax'

            BEGIN

            -- 定義total局部變量

            DECLARE total DECIMAL(8,2)

            DECLARE taxrate INT DEFAULT 6;

 

            -- 得到訂單的合計,並將結果存儲到局部變量total中

            SELECT Sum(item_price*quantity)

            FROM orderitems

            WHERE order_num = onumber

            INTO total;

 

            -- 判斷是否須要增長營業稅,如爲真,這增長6%的營業稅

            IF taxable THEN

            SELECT total+(total/100*taxrate) INTO total;

                  END IF;

            -- 把局部變量total中才合計傳給ototal中

            SELECT total INTO ototal;

            END;

            此存儲過程有很大的變更,首先,增長了註釋(前面放置--)。在存儲過程複雜性增長時,這樣很重要。在存儲體中,用DECLARE語句定義了兩個局部變量。DECLARE要求制定變量名和數據類型,它也支持可選的默認值(這個例子中taxrate的默認設置爲6%),SELECT 語句已經改變,所以其結果存儲到total局部變量中而不是ototal。IF語句檢查taxable是否爲真,若是爲真,則用另外一SELECT語句增長營業稅到局部變量total,最後用另外一SELECT語句將total(增長了或沒有增長的)保存到ototal中。

    COMMENT關鍵字  本列中的存儲過程在CREATE PROCEDURE 語句中包含了一個COMMENT值,他不是必需的,但若是給出,將在SHOW PROCEDURE STATUS的結果中顯示

    IF語句   這個例子中給出了MySQL的IF語句的基本用法。IF語句還支持ELSEIF和ELSE子句(前者還使用THEN子句,後者不使用)

    檢查存儲過程

        爲顯示用來建立一個存儲過程的CREATE語句,使用SHOW CREATE PROCEDURE語句

            SHOW CREATE PROCEDURE ordertotal;

        爲了得到包括什麼時候、有誰建立等詳細信息的存儲過程列表。使用SHOW PROCEDURE STATUS.限制過程狀態結果,爲了限制其輸出,可使用LIKE指定一個過濾模式,例如:SHOW PROCEDURE STATUS LIKE ''ordertotal;


 

第二十四章  使用遊標

    MySQL5添加了對遊標的支持

    只能用於存儲過程

    由前幾章可知,mysql檢索操做返回一組稱爲結果集的行。都與mysql語句匹配的行(0行或多行),使用簡單的SELECT語句,沒有辦法獲得第一行、下一行或前10行,也不存在每次行地處理全部行的簡單方法(相對於成批處理他們)

    有時,須要在檢索出來的行中前進或後退一行或多行。這就是使用遊標的緣由。遊標(cursor)是一個存儲在MYSQL服務器上的數據庫查詢,它不是一條SELECT語句,而是被該語句檢索出來的結果集。在存儲了遊標以後,應用程序能夠根據須要滾動或瀏覽其中的數據。

    遊標主要用於交互式應用,其中用戶須要滾動屏幕上的數據,並對數據進行瀏覽或作出更改。

    使用遊標

        使用遊標涉及幾個明確的步驟:

            1 在可以使用遊標前,必須聲明(定義)它,這個過程實際上沒有檢索數據,它只是定義要使用的SELECT語句

            2 一旦聲明後,必須打開遊標以供使用。這個過程用錢嗎定義的SELECT語句吧數據實際檢索出來

            3 對於填有數據的遊標,根據須要取出(檢索)的各行

            4 在接受遊標使用時,必須關閉它 若是不明確關閉遊標,MySQL將會在到達END語句時自動關閉它

    建立遊標

        遊標可用DECLARE 語句建立。 DECLARE命名遊標,並定義相應的SELECT語句。根據須要選擇帶有WHERE和其餘子句。如:下面第一名爲ordernumbers的遊標,使用了檢索全部訂單的SELECT語句

            CREATE PROCEDURE processorders()

            BEGIN

            DECLARE ordernumbers CURSOR

            FOR

            SELECT order_num FROM orders ;

            END;

            存儲過程處理完成後,遊標就消失,由於它侷限於存儲過程

    打開和關閉遊標

            CREATE PROCEDURE processorders()

            BEGIN

            DECLAREordernumbers CURSOR

            FOR

            SELECT order_num FROM orders ;

            Open ordernumbers ;

            Close ordernumbers ;  //CLOSE釋放遊標使用的全部內部內存和資源,所以,每一個遊標不須要時都應該關閉

            END;

    使用遊標數據

        在一個遊標被打開後,可使用FETCH語句分別訪問它的每一行。FETCH指定檢索什麼數據(所需的要列),檢索出來的數據存儲在什麼地方。它還向前移動遊標中的內部行指針,使下一條FETCH語句檢索下一行,至關於PHP中的each()函數

循環檢索數據,從第一行到最後一行

            CREATE PROCEDURE processorders()

            BEGIN

            -- 聲明局部變量

            DECLARE done BOOLEAN DEFAULT 0;

            DECLARE o INT;

 

            DECLAREordernumbers CURSOR

            FOR

            SELECT order_num FROM orders ;

            -- 當SQLSTATE爲02000時設置done值爲1

            DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done=1;

            --打開遊標

            Open ordernumbers ;

            -- 開始循環

            REPEAT

            -- 把當前行的值賦給聲明的局部變量o中

            FETCH ordernumbers INTO o;

            -- 當done爲真時中止循環

            UNTIL done END REPEAT;

            --關閉遊標

            Close ordernumbers ;  //CLOSE釋放遊標使用的全部內部內存和資源,所以,每一個遊標不須要時都應該關閉

            END;

        語句中定義了CONTINUE HANDLER ,它是在條件出現時被執行的代碼。這裏,它指出當SQLSTATE '02000'出現時,SET done=1。SQLSTATE '02000'是一個未找到條件,當REPEAT沒有更多的行供循環時,出現這個條件。

    DECLARE 語句次序  用DECLARE語句定義局部變量必須在定義任意遊標或句柄以前定義,而句柄必須在遊標以後定義。不遵照此規則就會出錯

重複和循環   除這裏使用REPEAT語句外,MySQL還支持循環語句,它可用來重複執行代碼,直到使用LEAVE語句手動退出爲止。一般REPEAT語句的語法使它更適合於對遊標進行的循環。

爲了把這些內容組織起來,此次吧取出的數據進行某種實際的處理

        CREATE PROCEDURE processorders()

        BEGIN

        -- 聲明局部變量

        DECLARE done BOOLEAN DEFAULT 0;

        DECLARE o INT;

        DECLARE t DECIMAL(8,2)

 

        DECLAREordernumbers CURSOR

        FOR

        SELECT order_num FROM orders ;

        -- 當SQLSTATE爲02000時設置done值爲1

        DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done=1;

        -- 建立一個ordertotals的表

        CREATE TABLE IF NOT EXISTS ordertotals( order_num INT , total DECIMAL(8,2))

        --打開遊標

        Open ordernumbers ;

        -- 開始循環

        REPEAT

        -- 把當前行的值賦給聲明的局部變量o中

        FETCH ordernumbers INTO o;

        -- 用上文講到的ordertotal存儲過程並傳入參數,返回營業稅計算後的合計傳給t變量

        CALL ordertotal(o , 1 ,t)

        -- 把訂單號和合計插入到新建的ordertotals表中

        INSERT INTO ordertotals(order_num, total) VALUES(o , t);

        -- 當done爲真時中止循環

        UNTIL done END REPEAT;

        --關閉遊標

        Close ordernumbers ;  //CLOSE釋放遊標使用的全部內部內存和資源,所以,每一個遊標不須要時都應該關閉

        END;

        最後SELECT * FROM ordertotals就能查看結果了


 

第二十五章 使用觸發器

    MySQL5版本後支持觸發器

    只有表支持觸發器,視圖不支持觸發器

    MySQL語句在須要的時被執行,存儲過程也是如此,可是若是你想要某條語句(或某些語句)在事件發生時自動執行,那該怎麼辦呢:例如:

        1 每增長一個顧客到某個數據庫表時,都檢查其電話號碼格式是否正確,區的縮寫是否爲大寫

        2 每當訂購一個產品時,都從庫存數量中減小訂購的數量

        3 不管什麼時候刪除一行,都在某個存檔中保留一個副本

    這寫例子的共同之處是他們都須要在某個表發生更改時自動處理。這就是觸發器。觸發器是MySQL響應一下任意語句而自動執行的一條MySQL語句(或位於BEGIN和END語句之間的一組語句)

    1 DELETE

    2 INSERT

    3 UPDATE

    其餘的MySQL語句不支持觸發器

   建立觸發器

        建立觸發器須要給出4條信息

        1 惟一的觸發器名;  //保存每一個數據庫中的觸發器名惟一

        2 觸發器關聯的表;

        3 觸發器應該響應的活動(DELETE、INSERT或UPDATE)

        4 觸發器什麼時候執行(處理前仍是後,前是BEFORE 後是AFTER)

        建立觸發器用CREATE TRIGGER

        CREATE TRIGGER newproduct AFTER INSERT ON products

        FOR EACH ROW SELECT'Product added'

       建立新觸發器newproduct ,它將在INSERT語句成功執行後執行。這個觸發器還鎮定FOR EACH ROW,所以代碼對每一個插入的行執行。這個例子做用是文本對每一個插入的行顯示一次product added

        FOR EACH ROW 針對每一個行都有做用,避免了INSERT一次插入多條語句

   觸發器定義規則

        觸發器按每一個表每一個事件每次地定義,每一個表每一個事件每次只容許定義一個觸發器,所以,每一個表最多定義6個觸發器(每條INSERT UPDATE 和DELETE的以前和以後)。單個觸發器不能與多個事件或多個表關聯,因此,若是你須要一個對INSERT 和UPDATE存儲執行的觸發器,則應該定義兩個觸發器

   觸發器失敗  若是BEFORE(以前)觸發器失敗,則MySQL將不執行SQL語句的請求操做,此外,若是BEFORE觸發器或語句自己失敗,MySQL將不執行AFTER(以後)觸發器

   刪除觸發器

        DROP TRIGGER newproduct;

        觸發器不能更新或覆蓋,因此修改觸發器只能先刪除再建立

   使用觸發器

        咱們來看看每種觸發器以及它們的差異

    INSERT 觸發器

        INSERT觸發器在INSERT語句執行以前或以後執行。須要知道如下幾點:

    1 在INSERT觸發器代碼內,可引用一個名爲NEW的虛擬表,訪問被插入的行

    2 在BEFORE INSERT觸發器中,NEW中的值也能夠被更新(容許更改插入的值)

    3 對於AUTO_INCREMENT列,NEW在INSERT執行以前包含0,在INSERT執行以後包含新的自動生成值

       提示:一般BEFORE用於數據驗證和淨化(目的是保證插入表中的數據確實是須要的數據)。本提示也適用於UPDATE觸發器

   DELETE 觸發器

        DELETE觸發器在語句執行以前仍是以後執行,須要知道如下幾點:

    1 在DELETE觸發器代碼內,你能夠引用一個名爲OLD的虛擬表,訪問被刪除的行;

    2 OLD中的值所有是隻讀的,不能更新

        例子演示適用OLD保存將要除的行到一個存檔表中

        CREATE TRIGGERdeleteorder BEFORE DELETE ON orders

        FOR EACH ROW

        BEGIN  

        INSERT INTO archive_orders(order_num , order_date , cust_id)

        VALUES(OLD.order_num , OLD.order_date , OLD.cust_id);

        END;

        //此處的BEGIN  END塊是非必需的,能夠沒有

    在任何訂單刪除以前執行這個觸發器,它適用一條INSERT語句將OLD中的值(將要刪除的值)保存到一個名爲archive_orders的存檔表中

    BEFORE DELETE觸發器的優勢是(相對於AFTER DELETE觸發器),若是因爲某種緣由,訂單不能被存檔,DELETE自己將被放棄執行。

   多語言觸發器  正如上面所見,觸發器deleteorder 使用了BEGIN和END語句標記觸發器體。這在此例中並非必需的,不過也沒有害處。使用BEGIN  END塊的好處是觸發器能容納多條SQL語句。

   UPDATE觸發器

        UPDATE觸發器在語句執行以前仍是以後執行,須要知道如下幾點:

        1 在UPDATE觸發器代碼中,你能夠引用一個名爲OLD的虛擬表訪問(UPDATE語句前)的值,引用一名爲NEW的虛擬表訪問新更新的值

        2 在BEFORE UPDATE觸發器中,NEW中的值可能被更新,(容許更改將要用於UPDATE語句中的值)

        3 OLD中的值全都是隻讀的,不能更新

            例子:保證州名的縮寫老是大寫(無論UPDATE語句給出的是大寫仍是小寫)

            CREATE TRIGGER updatevendor BEFORE UPDATE ON vendores FOR EACH ROW SET NEW.vend_state = Upper(NEW.vend_state)

    觸發器的進一步介紹

    1 與其餘DBMS相比,MySQL5中支持的觸發器至關初級。之後可能會加強

    2 建立觸發器可能須要特殊的安全訪問權限,可是觸發器的執行時自動的.若是INSERT UPDATE DELETE能執行,觸發器就能執行

    3 應該用觸發器來保證數據的一致性(大小寫、格式等)。在觸發器中執行這種類型的處理的優勢是它老是進行這個處理,並且是透明地進行,與客戶機應用無關

    4 觸發器的一種很是有意義的使用建立審計跟蹤。使用觸發器把更改(若是須要,甚至還有以前和以後的狀態)記錄到另外一表很是容易

    5 遺憾的是,MySQL觸發器中不支持CALL語句,這表示不能從觸發器中調用存儲過程。所須要的存儲過程代碼須要複製到觸發器內

相關文章
相關標籤/搜索