《SQL必知必會(huì)》筆記9-使用視圖view、存儲(chǔ)過程procedure

1 使用視圖(VIEW)

1.1 視圖

視圖是虛擬的表,只包含使用時(shí)動(dòng)態(tài)檢索數(shù)據(jù)的查詢。

視圖的常見應(yīng)用:

  • 重用SQL語(yǔ)句。
  • 簡(jiǎn)化復(fù)雜的SQL操作。在編寫查詢后,可以方便地重用它而不必知道其基本查詢細(xì)節(jié)。
  • 使用表的一部分而不是整個(gè)表。
  • 保護(hù)數(shù)據(jù)。可以授予用戶訪問表的特定部分的權(quán)限,而不是整個(gè)表的訪問權(quán)限。
  • 更改數(shù)據(jù)格式和提示。視圖可返回與底層表的表示和格式不同的數(shù)據(jù)。

創(chuàng)建視圖之后,可以用與表基本相同的方式使用它們。可以對(duì)視圖執(zhí)行SELECT操作,過濾和排序數(shù)據(jù),將視圖聯(lián)結(jié)到其他視圖或表,甚至添加和更新數(shù)據(jù)。

創(chuàng)建和使用視圖的一些常見規(guī)則和限制:

  • 與表一樣,視圖必須唯一命名,不能給視圖取與別的視圖或表相同的名字。
  • 對(duì)于可以創(chuàng)建的視圖數(shù)目沒有限制。
  • 創(chuàng)建視圖,必須有足夠的訪問權(quán)限。
  • 視圖可以嵌套,可以利用從其他視圖中檢索數(shù)據(jù)的查詢來構(gòu)造視圖。
  • 視圖不能索引,也不能有關(guān)聯(lián)的觸發(fā)器或默認(rèn)值。
  • 有些DBMS把視圖作為只讀的查詢,這表示可以從視圖檢索數(shù)據(jù),但不能將數(shù)據(jù)寫回底層表。

1.2 創(chuàng)建視圖CREATE VIEW

視圖是虛擬的表,只包含使用時(shí)動(dòng)態(tài)檢索數(shù)據(jù)的查詢。

  1. 視圖用CREATE VIEW語(yǔ)句來創(chuàng)建。
  2. 使用SHOW CREATE VIEW viewname;來查看創(chuàng)建視圖的語(yǔ)句。
  3. 用DROP刪除視圖,其語(yǔ)法為DROP VIEW viewname;。
  4. 更新視圖時(shí),可先用DROP再用CREATE,也可以直接用CREATE OR REPLACE VIEW。如果要更新的視圖不存在,則第2條更新語(yǔ)句會(huì)創(chuàng)建一個(gè)視圖;如果要更新的視圖存在,則第2條更新語(yǔ)句會(huì)替換原有視圖。

1.2.1 利用視圖簡(jiǎn)化復(fù)雜的聯(lián)結(jié)

常見的視圖應(yīng)用是隱藏復(fù)雜的SQL。

(1)先創(chuàng)建ProductCustomers視圖。

CREATE VIEW ProductCustomers AS
SELECT cust_name, cust_contact, prod_id
FROM Customers, Orders, OrderItems
WHERE Customers.cust_id = Orders.cust_id
AND OrderItems.order_num = Orders.order_num;

(2)檢索訂購(gòu)了產(chǎn)品RGAN01的顧客。

SELECT cust_name, cust_contact
FROM ProductCustomers
WHERE prod_id = 'RGAN01';

利用視圖,可一次性編寫基礎(chǔ)的SQL,然后根據(jù)需要多次使用。


1.2.2 用視圖重新格式化檢索出的數(shù)據(jù)

將供應(yīng)商Vendors表中的vend_name和vend_country合并輸出顯示。

CREATE VIEW VendorLocations AS
SELECT concat(RTRIM(vend_name), '(', RTRIM(vend_country), ')')
AS vend_title
FROM Vendors;

SELECT * 
FROM VendorLocations;

1.2.3 用視圖過濾不想要的數(shù)據(jù)

定義CustomerEmailList視圖,過濾沒有Email的顧客。

CREATE VIEW CustomerEmailList AS
SELECT cust_id, cust_name, cust_email
FROM Customers
WHERE cust_email IS NOT NULL;

SELECT * 
FROM CustomerEmailList;

1.2.4 使用視圖與計(jì)算字段

檢索某個(gè)訂單的產(chǎn)品,計(jì)算每種產(chǎn)品的總價(jià)格。

CREATE VIEW OrderItemsExpanded AS
SELECT order_num, prod_id, quantity, item_price,
       quantity * item_price AS expanded_price
FROM OrderItems;

SELECT *
FROM OrderItemsExpanded
WHERE order_num = 20008;

1.2.5 更新視圖

迄今為止的所有視圖都是和SELECT語(yǔ)句使用的。然而,視圖的數(shù)據(jù)能否更新?答案視情況而定。

通常,視圖是可更新的,即,可以對(duì)它們使用INSERT、UPDATE和DELETE。更新一個(gè)視圖將更新其基表,如果對(duì)視圖增加或者刪除行,實(shí)際上是對(duì)其基表增加或刪除行。

但是,并非所有視圖都是可更新的。基本上可以說,如果MySQL不能正確地確定被更新的基數(shù)據(jù),則不允許更新(包括插入和刪除)。

換句話說,如果視圖定義中有以下操作,則不能進(jìn)行視圖的更新。

  • 分組(使用GROUP BY和HAVING)。
  • 聯(lián)結(jié)。
  • 子查詢。
  • 并。
  • 聚集函數(shù)(MIN()、COUNT()等)。
  • DISTINCT。
  • 導(dǎo)出(計(jì)算)列。

換句話說,本章的許多例子的視圖都是不可更新的。這聽上去好像是一個(gè)嚴(yán)重的限制,但實(shí)際上不是,因?yàn)橐晥D主要用于數(shù)據(jù)檢索。

一般,應(yīng)該將視圖用于檢索(SELECT語(yǔ)句)而不用于更新(INSERT、UPDATE和DELETE)。


2 使用存儲(chǔ)過程

2.1 存儲(chǔ)過程

迄今為止,使用的大多數(shù)SQL語(yǔ)句都是針對(duì)一個(gè)或多個(gè)表的單條語(yǔ)句。并非所有操作都這么簡(jiǎn)單,經(jīng)常會(huì)有一個(gè)完整的操作需要多條語(yǔ)句才能完成。

比如,考慮以下情況:

  1. 為了處理訂單,需要核對(duì)以保證庫(kù)存中有相應(yīng)的物品。
  2. 如果庫(kù)存有物品,這些物品需要預(yù)定以便不將它們?cè)儋u給別的人,并且要減少可用的物品數(shù)量以及反映正確的庫(kù)存量。
  3. 庫(kù)存中沒有的物品需要訂購(gòu),這需要與供應(yīng)商進(jìn)行某種交互。
  4. 關(guān)于哪些物品入庫(kù)(并且可以立即發(fā)貨)和哪些物品退訂,需要通知相應(yīng)的客戶。

執(zhí)行上述的例子,需要針對(duì)許多表的多條SQL語(yǔ)句。此外,需要執(zhí)行的具體語(yǔ)句及其次序也不是固定的,它們可能會(huì)(和將)根據(jù)哪些物品在庫(kù)存中,哪些不在而變化。

存儲(chǔ)過程簡(jiǎn)單來說,就是為以后的使用而保存的一條或多條SQL語(yǔ)句的集合。可將其視為批文件,但它們的作用不限于批處理。


2.2 為什么要使用存儲(chǔ)過程

使用存儲(chǔ)過程的主要理由:

  1. 通過把處理封裝在容易使用的單元中,簡(jiǎn)化復(fù)雜的操作。
  2. 由于不要求反復(fù)建立一系列處理步驟,這保證了數(shù)據(jù)的完整性。如果所有開發(fā)人員和應(yīng)用程序都使用同一(試驗(yàn)和測(cè)試)存儲(chǔ)過程,則使用的代碼都是相同的。(這一點(diǎn)的延伸就是防止錯(cuò)誤,需要執(zhí)行的步驟越多,出錯(cuò)的可能性就越大。防止錯(cuò)誤保證了數(shù)據(jù)的一致性。)
  3. 簡(jiǎn)化對(duì)變動(dòng)的管理。如果表名、列名或業(yè)務(wù)邏輯有變化,只需要更改存儲(chǔ)過程的代碼,使用它的人員甚至不需要知道這些變化。(這一點(diǎn)的延伸就是安全性,通過存儲(chǔ)過程限制對(duì)基礎(chǔ)數(shù)據(jù)的訪問減少了數(shù)據(jù)訛誤的機(jī)會(huì)。)
  4. 提高性能。因?yàn)槭褂么鎯?chǔ)過程比使用簡(jiǎn)單的SQL語(yǔ)句要快。
  5. 存在一些只能用在單個(gè)請(qǐng)求中的MySQL元素和特性,存儲(chǔ)過程可以使用它們來編寫功能更強(qiáng)更靈活的代碼。

使用存儲(chǔ)過程的3個(gè)主要好處就是:簡(jiǎn)單、安全、高性能。

存在的缺陷:

  1. 一般來說,存儲(chǔ)過程的編寫比基本SQL語(yǔ)句復(fù)雜,編寫存儲(chǔ)過程需要更高的技能,更豐富的經(jīng)驗(yàn)。
  2. 可能沒有創(chuàng)建存儲(chǔ)過程的安全訪問權(quán)限。許多數(shù)據(jù)庫(kù)管理員限制存儲(chǔ)過程的創(chuàng)建權(quán)限,允許用戶使用存儲(chǔ)過程,但不允許他們創(chuàng)建存儲(chǔ)過程。

2.3 使用存儲(chǔ)過程

2.3.1 執(zhí)行存儲(chǔ)過程

MySQL稱存儲(chǔ)過程的執(zhí)行為調(diào)用,因此MySQL執(zhí)行存儲(chǔ)過程的語(yǔ)句為CALL。CALL接受存儲(chǔ)過程的名字以及需要傳遞給它的任意參數(shù)。

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

執(zhí)行名為productpricing的存儲(chǔ)過程,它計(jì)算并返回產(chǎn)品的最低、最高和平均價(jià)格。


2.3.2 創(chuàng)建存儲(chǔ)過程

CREATE PROCEDURE productpricing()
BEGIN
    SELECT AVG(prod_price) AS priceaverage
    FROM Products;
END;

由于默認(rèn)的MySQL語(yǔ)句分隔符為;,如果命令行實(shí)用程序要解釋存儲(chǔ)過程自身內(nèi)的;字符,則它們最終不會(huì)成為存儲(chǔ)過程的成分,這會(huì)導(dǎo)致存儲(chǔ)過程中的SQL出現(xiàn)句法錯(cuò)誤,正如上圖所示。

解決辦法就是使用更改命令行實(shí)用程序的語(yǔ)法分隔符,如下所示:

DELIMITER //          # 臨時(shí)改成//分隔符

CREATE PROCEDURE productpricing()
BEGIN
    SELECT AVG(prod_price) AS priceaverage
    FROM Products;
END//

DELIMITER ;     # 改成默認(rèn);分隔符,不然以后寫的SQL語(yǔ)句都要以//作為結(jié)尾,才不會(huì)報(bào)錯(cuò)。

調(diào)用存儲(chǔ)過程:

CALL productpricing();

CALL productpricing();執(zhí)行剛創(chuàng)建的存儲(chǔ)過程并顯示返回的結(jié)果。因?yàn)榇鎯?chǔ)過程實(shí)際上是一種函數(shù),所以存儲(chǔ)過程名后需要有()符號(hào),即使不傳遞參數(shù)也需要。

可以看作調(diào)用一個(gè)定義好的函數(shù),一定要帶()符號(hào)。


2.3.3 刪除存儲(chǔ)過程

刪除剛創(chuàng)建的存儲(chǔ)過程:

DROP PROCEDURE productpricing;

刪除存儲(chǔ)過程的時(shí)候,只需給出存儲(chǔ)過程名即可,不需要帶上()符號(hào)。

** 建議:如果指定的存儲(chǔ)過程不存在的話,則DROP PROCEDURE將會(huì)產(chǎn)生錯(cuò)誤,為防止出現(xiàn)錯(cuò)誤,可使用DROP PROCEDURE IF EXISTS。**

DROP PROCEDURE IF EXISTS productpricing;

2.3.4 使用帶參數(shù)的存儲(chǔ)過程

productpricing只是一個(gè)簡(jiǎn)單的存儲(chǔ)過程,它簡(jiǎn)單地顯示SELECT語(yǔ)句的結(jié)果。一般,存儲(chǔ)過程并不顯示結(jié)果,而是把結(jié)果返回給你指定的變量。

注意:創(chuàng)建下面的存儲(chǔ)過程的時(shí)候,記得先刪除以前創(chuàng)建的productpricing。

DELIMITER //

CREATE PROCEDURE productpricing(
    OUT pl DECIMAL(8,2),
    OUT ph DECIMAL(8,2),
    OUT pa DECIMAL(8,2)
)
BEGIN
    SELECT MIN(prod_price) INTO pl
    FROM Products;
    SELECT MAX(prod_price) INTO ph
    FROM Products;
    SELECT AVG(prod_price) INTO pa
    FROM Products;
END //

DELIMITER ;

此存儲(chǔ)過程接受3個(gè)參數(shù):pl存儲(chǔ)產(chǎn)品最低價(jià)格,ph存儲(chǔ)產(chǎn)品最高價(jià)格,pa存儲(chǔ)產(chǎn)品平均價(jià)格。

MySQL支持IN(傳遞給存儲(chǔ)過程)、OUT(從存儲(chǔ)過程傳出)和INOUT(對(duì)存儲(chǔ)過程傳入和傳出)類型的參數(shù)。

存儲(chǔ)過程的代碼位于BEGIN和END語(yǔ)句內(nèi),它們是一系列SELECT語(yǔ)句,用來檢索值,然后保存到相應(yīng)的變量(通過指定INTO關(guān)鍵字)。

為調(diào)用此存儲(chǔ)過程,必須指定3個(gè)變量名:

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

所有MySQL變量都必須以@開始。

為了顯示檢索出的產(chǎn)品平均價(jià)格:

SELECT @priceaverage;

為獲得3個(gè)值,可使用以下語(yǔ)句:

SELECT @pricehigh, @pricelow, @priceaverage;

創(chuàng)建另一個(gè)存儲(chǔ)過程,這次使用IN和OUT參數(shù)。ordertotal接受訂單號(hào)并返回該訂單的合計(jì):

DELIMITER //

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 //

DELIMITER ;

調(diào)用該存儲(chǔ)過程時(shí),必須給ordertotal傳遞兩個(gè)參數(shù):第一個(gè)參數(shù)為訂單號(hào),第二個(gè)參數(shù)為包含計(jì)算出來的合計(jì)的變量名。

CALL ordertotal(20005, @total);
SELECT @total;

CALL ordertotal(20009, @total);
SELECT @total;

2.3.5 建立智能存儲(chǔ)過程

上述的所有存儲(chǔ)過程基本上都是封裝MySQL簡(jiǎn)單的SELECT語(yǔ)句,只有在存儲(chǔ)過程內(nèi)包含業(yè)務(wù)規(guī)則和智能處理時(shí),它們的作用才能真正顯現(xiàn)出來。

考慮如下場(chǎng)景,你需要獲得與以前一樣的訂單合并,但需要對(duì)合計(jì)增加營(yíng)業(yè)稅,不過只針對(duì)某些顧客。那么,你需要做下面幾件事情:

  • 獲得合計(jì)。
  • 把營(yíng)業(yè)稅有條件地添加到合計(jì)。
  • 返回合計(jì)(帶稅或者不帶稅)。

存儲(chǔ)過程的完整工作如下(記得先刪除以前創(chuàng)建的ordertotal存儲(chǔ)過程):

DELIMITER //

CREATE PROCEDURE ordertotal(
    IN    onumber   INT,
    IN    taxable   BOOLEAN,
    OUT   ototal    DECIMAL(8,2)
)
BEGIN
    # 聲明局部變量
    DECLARE total    DECIMAL(8,2);
    DECLARE taxrate  INT   DEFAULT  6;

    SELECT SUM(item_price * quantity)
    FROM OrderItems
    WHERE order_num = onumber
    INTO total;

    IF taxable THEN
        SELECT total + (total/100 * taxrate) INTO total;
    END IF;

    # 結(jié)果保存到ototal中
    SELECT total INTO ototal;
END //

DELIMITER ;

DECLARE語(yǔ)句定義了兩個(gè)局部變量,DECLARE要求指定變量名和數(shù)據(jù)類型,它支持可選的默認(rèn)值。IF語(yǔ)句檢查taxable是否為真,如果為真,則用另一個(gè)SELECT語(yǔ)句增加營(yíng)業(yè)稅到局部變量total。最后,將局部變量total保存到ototal。

調(diào)用該存儲(chǔ)過程:

CALL ordertotal(20005, 0, @total);
SELECT @total;

CALL ordertotal(20005, 1, @total);
SELECT @total;

2.3.6 檢查存儲(chǔ)過程

為顯示用來創(chuàng)建一個(gè)存儲(chǔ)過程的CREATE語(yǔ)句,使用SHOW CREATE PROCEDURE語(yǔ)句:

SHOW CREATE PROCEDURE ordertotal;

為了獲得包括何時(shí)、由誰(shuí)創(chuàng)建等詳細(xì)信息的存儲(chǔ)過程列表,使用SHOW PROCEDURE STATUS。

SHOW PROCEDURE STATUS;

可看出,SHOW PROCEDURE STATUS;顯示了太多無(wú)關(guān)緊要的信息,為限制其輸出,可以使用LIKE指定一個(gè)過濾模式。例如:

SHOW PROCEDURE STATUS LIKE 'ordertotal';

如果您發(fā)現(xiàn)文中有不清楚或者有問題的地方,請(qǐng)?jiān)谙路皆u(píng)論區(qū)留言,我會(huì)根據(jù)您的評(píng)論,更新文中相關(guān)內(nèi)容,謝謝!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,517評(píng)論 6 539
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,087評(píng)論 3 423
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,521評(píng)論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,493評(píng)論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,207評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,603評(píng)論 1 325
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,624評(píng)論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,813評(píng)論 0 289
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,364評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,110評(píng)論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,305評(píng)論 1 371
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,874評(píng)論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,532評(píng)論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,953評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,209評(píng)論 1 291
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,033評(píng)論 3 396
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,268評(píng)論 2 375

推薦閱讀更多精彩內(nèi)容