关系数据库——视图/存储过程/触发器
視圖
視圖是虛擬的表,與包含數(shù)據(jù)的表不同,視圖只包含使用時(shí)動(dòng)態(tài)檢索數(shù)據(jù)的查詢(xún),主要是用于查詢(xún)。
為什么使用視圖
注意:
- 在視圖創(chuàng)建之后,可以用與表基本相同的方式利用它們??梢詫?duì)視圖執(zhí)行select操作,過(guò)濾和排序數(shù)據(jù),將視圖聯(lián)結(jié)到其他視圖或表,甚至能添加和更新數(shù)據(jù)。
- 重要的是知道視圖僅僅是用來(lái)查看存儲(chǔ)在別處的數(shù)據(jù)的一種設(shè)施。視圖本身不包含數(shù)據(jù),因此它們返回的數(shù)據(jù)時(shí)從其他表中檢索出來(lái)的。在添加和更改這些表中的數(shù)據(jù)時(shí),視圖將返回改變過(guò)的數(shù)據(jù)。
- 因?yàn)橐晥D不包含數(shù)據(jù),所以每次使用視圖時(shí),都必須處理查詢(xún)執(zhí)行時(shí)所需的任一檢索。如果你使用多個(gè)聯(lián)結(jié)和過(guò)濾創(chuàng)建了復(fù)雜的視圖或者嵌套了視圖,可能會(huì)發(fā)現(xiàn)性能下降得很厲害。因此,在部署使用了大量視圖的應(yīng)用前,應(yīng)該進(jìn)行測(cè)試。
視圖的規(guī)則和限制
視圖的創(chuàng)建
視圖的更新
視圖是否可以更新,要視情況而定。
通常情況下視圖是可以更新的,可以對(duì)他們進(jìn)行insert,update和delete。更新視圖就是更新其基表(視圖本身沒(méi)有數(shù)據(jù))。如果你對(duì)視圖進(jìn)行增加或者刪除行,實(shí)際上就是對(duì)基表進(jìn)行增加或者刪除行。
但是,如果MySQL不能正確的確定更新的基表數(shù)據(jù),則不允許更新(包括插入和刪除),這就意味著視圖中如果存在以下操作則不能對(duì)視圖進(jìn)行更新:(1)分組(使用group by 和 having );(2)聯(lián)結(jié);(3)子查詢(xún);(4)并;(5)聚集函數(shù);(6)dictinct;(7)導(dǎo)出(計(jì)算)列。
?
存儲(chǔ)過(guò)程
存儲(chǔ)過(guò)程就是為了以后的使用而保存的一條或者多條MySQL語(yǔ)句的集合。可將視為批文件,雖然他們的作用不僅限于批處理。
為什么使用儲(chǔ)存過(guò)程?
1.通過(guò)把處理封裝在容易使用的單元中,簡(jiǎn)化復(fù)雜的操作;
?
2.由于不要求反復(fù)建立一系列處理步驟,保證了數(shù)據(jù)的完整性。如果所有開(kāi)發(fā)人員和應(yīng)用程序都使用同一(實(shí)驗(yàn)和測(cè)試)存儲(chǔ)過(guò)程,則所使用的代碼都是相同的。這一點(diǎn)的延伸就是防止錯(cuò)誤。需要執(zhí)行的步驟越多,出錯(cuò)的可能性就越大,防止錯(cuò)誤保證了數(shù)據(jù)的一致性。
?
3.簡(jiǎn)化對(duì)變動(dòng)的管理,如果表名。列名或者業(yè)務(wù)邏輯等有變化,只需要更改存儲(chǔ)過(guò)程的代碼。使用它的人員甚至不需要知道這些變化。這一點(diǎn)延伸就是安全性,通過(guò)存儲(chǔ)過(guò)程限制對(duì)基數(shù)據(jù)的訪(fǎng)問(wèn)減少了數(shù)據(jù)訛誤的機(jī)會(huì)。
?
4.提高性能。因?yàn)槭褂么鎯?chǔ)過(guò)程比使用單獨(dú)的sql語(yǔ)句更快。
?
5.存在一些只能用在單個(gè)請(qǐng)求的MySQL元素和特性,存儲(chǔ)過(guò)程可以使用他們來(lái)編寫(xiě)功能更強(qiáng)更靈活的代碼
?
綜上:
三個(gè)主要的好處:簡(jiǎn)單、安全、高性能。
兩個(gè)缺陷:
1、存儲(chǔ)過(guò)程的編寫(xiě)更為復(fù)雜,需要更高的技能更豐富的經(jīng)驗(yàn)。
2、可能沒(méi)有創(chuàng)建存儲(chǔ)過(guò)程的安全訪(fǎng)問(wèn)權(quán)限。許多數(shù)據(jù)庫(kù)管理員限制存儲(chǔ)過(guò)程的 創(chuàng)建權(quán)限,允許使用,不允許創(chuàng)建。
執(zhí)行存儲(chǔ)過(guò)程
Call關(guān)鍵字:Call接受存儲(chǔ)過(guò)程的名字以及需要傳遞給他的任意參數(shù)。存儲(chǔ)過(guò)程可以顯示結(jié)果,也可以不顯示結(jié)果。
CREATE PROCEDURE productpricing()
??? BEGIN
??????? SELECT? AVG( prod_price)? as priceaverage FROM products;
??? END;
創(chuàng)建名為productpricing的儲(chǔ)存過(guò)程。如果存儲(chǔ)過(guò)程中需要傳遞參數(shù),則將他們?cè)诶ㄌ?hào)中列舉出來(lái)即可。括號(hào)必須有。BEGIN和END關(guān)鍵字用來(lái)限制存儲(chǔ)過(guò)程體。上述存儲(chǔ)過(guò)程體本身是一個(gè)簡(jiǎn)單的select語(yǔ)句。注意這里只是創(chuàng)建存儲(chǔ)過(guò)程并沒(méi)有進(jìn)行調(diào)用。
?
儲(chǔ)存過(guò)程的使用:
?
Call productpring();
?
使用參數(shù)的存儲(chǔ)過(guò)程
一般存儲(chǔ)過(guò)程并不顯示結(jié)果,而是把結(jié)果返回給你指定的變量上。
變量:內(nèi)存中一個(gè)特定的位置,用來(lái)臨時(shí)存儲(chǔ)數(shù)據(jù)。
MySQL> CREATE PROCEDURE prod(out pl decimal(8,2),out ph decimal(8,2),out pa decimal(8,2)) beginselect Min(prod_price) into pl from products;select MAx(prod_price) into ph from products;select avg(prod_price) into pa from products;end;call PROCEDURE(@pricelow,@pricehigh,@priceaverage);select @pricelow;select @pricehigh;select @pricelow,@pricehigh,@priceaverage;?
解釋:
此存儲(chǔ)過(guò)程接受3個(gè)參數(shù),pl存儲(chǔ)產(chǎn)品最低價(jià),ph存儲(chǔ)產(chǎn)品最高價(jià),pa存儲(chǔ)產(chǎn)品平均價(jià)。每個(gè)參數(shù)必須指定類(lèi)型,使用的為十進(jìn)制,關(guān)鍵字OUT 指出相應(yīng)的參數(shù)用來(lái)從存儲(chǔ)過(guò)程傳出一個(gè)值(返回給調(diào)用者)。
?
MySQL支持in(傳遞給存儲(chǔ)過(guò)程)、out(從存儲(chǔ)過(guò)程傳出,這里所用)和inout(對(duì)存儲(chǔ)過(guò)程傳入和傳出)類(lèi)型的參數(shù)。存儲(chǔ)過(guò)程的代碼位于begin和end語(yǔ)句內(nèi)。他們是一系列select語(yǔ)句,用來(lái)檢索值。然后保存到相對(duì)應(yīng)的變量(通過(guò)INTO關(guān)鍵字)。
存儲(chǔ)過(guò)程的參數(shù)允許的數(shù)據(jù)類(lèi)型與表中使用的類(lèi)型相同。注意記錄集是不被允許的類(lèi)型,因此,不能通過(guò)一個(gè)參數(shù)返回多個(gè)行和列,這也是上面為什么要使用3個(gè)參數(shù)和3條select語(yǔ)句的原因。
?
調(diào)用:為調(diào)用此存儲(chǔ)過(guò)程,必須指定3個(gè)變量名。如上所示。3個(gè)參數(shù)是存儲(chǔ)過(guò)程保存結(jié)果的3個(gè)變量的名字。調(diào)用時(shí),語(yǔ)句并不顯示任何數(shù)據(jù),它返回以后可以顯示的變量(或在其他處理中使用)。
?
注意:所有的MySQL變量都是以@開(kāi)頭。
CREATE PROCEDURE ordertotal(IN innumber int,OUT outtotal decimal(8,2))BEGINSELECT Sum(item_price * quantity) FROM orderitems WHERE order_num = innumber INTO outtotal;end??? //CALL ordertotal(20005,@total);select @total;? // 得到20005訂單的合計(jì)CALL ordertotal(20009,@total);select @total; //得到20009訂單的合計(jì)?
帶有控制語(yǔ)句的存儲(chǔ)過(guò)程
?? 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 totalDECLARE total DECIMAL(8,2);-- declear tax percentageDECLARE taxrate INT DEFAULT 6;-- get the order totalSELECT Sum(item_price * quantity) FROM orderitems WHERE order_num = onumber INTO total;-- IS this taxable?IF taxable THEN-- yes ,so add taxrate to the totalSELECT total+(total/100*taxrate)INTO total;END IF;-- finally ,save to out variableSELECT total INTO ototal;END;在存儲(chǔ)過(guò)程中我們使用了DECLARE語(yǔ)句,他們表示定義兩個(gè)局部變量,DECLARE要求指定變量名和數(shù)據(jù)類(lèi)型。它也支持可選的默認(rèn)值(taxrate默認(rèn)6%),因?yàn)楹笃谖覀冞€要判斷要不要增加稅,所以,我們把SELECT查詢(xún)的結(jié)果存儲(chǔ)到局部變量total中,然后在IF 和THEN的配合下,檢查taxable是否為真,然后在真的情況下,我們利用另一條SELECT語(yǔ)句增加營(yíng)業(yè)稅到局部變量total中,然后我們?cè)倮肧ELECT語(yǔ)句將total(增加稅或者不增加稅的結(jié)果)保存到總的ototal中。
COMMENT關(guān)鍵字 上面的COMMENT是可以給出或者不給出,如果給出,將在SHOW PROCEDURE STATUS的結(jié)果中顯示。
?
觸發(fā)器
在某個(gè)表發(fā)生更改時(shí)自動(dòng)處理某些語(yǔ)句,這就是觸發(fā)器。
?
觸發(fā)器是MySQL響應(yīng)delete 、update 、insert 、位于begin 和end語(yǔ)句之間的一組語(yǔ)句而自動(dòng)執(zhí)行的一條MySQL語(yǔ)句。其他的語(yǔ)句不支持觸發(fā)器。
創(chuàng)建觸發(fā)器
在創(chuàng)建觸發(fā)器時(shí),需要給出4條語(yǔ)句(規(guī)則):
1.? 唯一的觸發(fā)器名;
2.? 觸發(fā)器關(guān)聯(lián)的表;
3.? 觸發(fā)器應(yīng)該響應(yīng)的活動(dòng);
4.? 觸發(fā)器何時(shí)執(zhí)行(處理之前或者之后)
?
Create trigger 語(yǔ)句創(chuàng)建 觸發(fā)器
CREATE TRIGGER newproduct AFTER INSERT ON products FOR EACH ROW SELECT 'Product added' INTO @info;
CREATE TRIGGER用來(lái)創(chuàng)建名為newproduct的新觸發(fā)器。觸發(fā)器可以在一個(gè)操作發(fā)生前或者發(fā)生后執(zhí)行,這里AFTER INSERT 是指此觸發(fā)器在INSERT語(yǔ)句成功執(zhí)行后執(zhí)行。這個(gè)觸發(fā)器還指定FOR EACH ROW , 因此代碼對(duì)每個(gè)插入行都會(huì)執(zhí)行。文本Product added 將對(duì)每個(gè)插入的行顯示一次。
?
注意:
1、觸發(fā)器只有表才支持,視圖,臨時(shí)表都不支持觸發(fā)器。
2、觸發(fā)器是按照每個(gè)表每個(gè)事件每次地定義,每個(gè)表每個(gè)事件每次只允許一個(gè)觸發(fā)器,因此,每個(gè)表最多支持六個(gè)觸發(fā)器(insert,update,delete的before 和after)。
3、單一觸發(fā)器不能與多個(gè)事件或多個(gè)表關(guān)聯(lián),所以,你需要一個(gè)對(duì)insert和update 操作執(zhí)行的觸發(fā)器,則應(yīng)該定義兩個(gè)觸發(fā)器。
4、觸發(fā)器失敗:如果before 觸發(fā)器失敗,則MySQL將不執(zhí)行請(qǐng)求的操作,此外,如果before觸發(fā)器或者語(yǔ)句本身失敗,MySQL則將不執(zhí)行after觸發(fā)器。
觸發(fā)器類(lèi)別
INSERT觸發(fā)器
是在insert語(yǔ)句執(zhí)行之前或者執(zhí)行之后被執(zhí)行的觸發(fā)器。
1、在insert觸發(fā)器代碼中,可引入一個(gè)名為new的虛擬表,訪(fǎng)問(wèn)被插入的行;
2、在before insert觸發(fā)器中,new中的值也可以被更新(允許更改被插入的值);
3、對(duì)于auto_increment列,new在insert執(zhí)行之前包含0,在insert執(zhí)行之后包含新的自動(dòng)生成值
CREATE TRIGGER neworder AFTER INSERT ON orders FOR EACH ROW SELECT NEW.order_num;
創(chuàng)建一個(gè)名為neworder的觸發(fā)器,按照AFTER INSERT ON orders 執(zhí)行。在插入一個(gè)新訂單到orders表時(shí),MySQL生成一個(gè)新的訂單號(hào)并保存到order_num中。觸發(fā)器從NEW.order_num取得這個(gè)值并返回它。此觸發(fā)器必須按照AFTER INSERT執(zhí)行,因?yàn)樵贐EFORE INSERT語(yǔ)句執(zhí)行之前,新order_num還沒(méi)有生成。對(duì)于orders的每次插入使用這個(gè)觸發(fā)器總是返回新的訂單號(hào)。
DELETE觸發(fā)器
Delete觸發(fā)器在delete語(yǔ)句執(zhí)行之前或者之后執(zhí)行。
1、在delete觸發(fā)器的代碼內(nèi),可以引用一個(gè)名為OLD的虛擬表,用來(lái)訪(fǎng)問(wèn)被刪除的行。
2、OLD中的值全為只讀,不能更新。
CREATE TRIGGER deleteorder BEFORE DELETE ON orders FOR EACH ROWBEGININSERT INTO archive_orders(order_num,order_date,cust_id) values (OLD.order_num,OLD.order_date,OLD.cust_id);END;----------------------------------------------------------------CREATE TABLE archive_orders(order_num int(11) NOT NULL AUTO_INCREMENT,order_date datetime NOT NULL,cust_id int(11) NOT NULL,PRIMARY KEY (order_num),KEY fk_orders1_customers1 (cust_id),CONSTRAINT fk_orders1_customers1 FOREIGN KEY (cust_id) REFERENCES customers(cust_id)) ENGINE=InnoDB AUTO_INCREMENT=20011 DEFAULT CHARSET=utf8在任意訂單被刪除前將執(zhí)行此觸發(fā)器,它使用一條INSERT 語(yǔ)句將OLD中的值(要被刪除的訂單) 保存到一個(gè)名為archive_orders的存檔表中(為實(shí)際使用這個(gè)例子,我們需要用與orders相同的列創(chuàng)建一個(gè)名為archive_orders的表)
?
使用BEFORE DELETE觸發(fā)器的優(yōu)點(diǎn)(相對(duì)于AFTER DELETE觸發(fā)器來(lái)說(shuō))為,如果由于某種原因,訂單不能存檔,delete本身將被放棄。
?
我們?cè)谶@個(gè)觸發(fā)器使用了BEGIN和END語(yǔ)句標(biāo)記觸發(fā)器體。這在此例子中并不是必須的,只是為了說(shuō)明使用BEGIN END 塊的好處是觸發(fā)器能夠容納多條SQL 語(yǔ)句(在BEGIN END塊中一條挨著一條)。
UPDATE觸發(fā)器
在update語(yǔ)句執(zhí)行之前或者之后執(zhí)行
1、在update觸發(fā)器的代碼內(nèi),可以引用一個(gè)名為OLD的虛擬表,用來(lái)訪(fǎng)問(wèn)以前(UPDATE語(yǔ)句之前)的值,引用一個(gè)名為NEW的虛擬表訪(fǎng)問(wèn)新更新的值。
2、在BEFORE UPDATE觸發(fā)器中,NEW中的值可能也被用于更新(允許更改將要用于UPDATE語(yǔ)句中的值)
3、OLD中的值全為只讀,不能更新。
CREATE TRIGGER updatevendor BEFORE UPDATE ON vendors FOR EACH ROW SET NEW.vend_state = Upper(NEW.vemd_state);
保證州名縮寫(xiě)總是大寫(xiě)(不管UPFATE語(yǔ)句中是否給出了大寫(xiě)),每次更新一行時(shí),NEW.vend_state中的值(將用來(lái)更新表行的值)都用Upper(NEW.vend_state)替換。
總結(jié)
1、通常before用于數(shù)據(jù)的驗(yàn)證和凈化(為了保證插入表中的數(shù)據(jù)確實(shí)是需要的數(shù)據(jù)) 也適用于update觸發(fā)器。
2、與其他DBMS相比,MySQL 5中支持的觸發(fā)器相當(dāng)初級(jí),未來(lái)的MySQL版本中估計(jì)會(huì)存在一些改進(jìn)和增強(qiáng)觸發(fā)器的支持。
3、創(chuàng)建觸發(fā)器可能需要特殊的安全訪(fǎng)問(wèn)權(quán)限,但是觸發(fā)器的執(zhí)行時(shí)自動(dòng)的,如果insert,update,或者delete語(yǔ)句能夠執(zhí)行,則相關(guān)的觸發(fā)器也能執(zhí)行。
4、用觸發(fā)器來(lái)保證數(shù)據(jù)的一致性(大小寫(xiě),格式等)。在觸發(fā)器中執(zhí)行這種類(lèi)型的處理的優(yōu)點(diǎn)就是它總是進(jìn)行這種處理,而且透明的進(jìn)行,與客戶(hù)機(jī)應(yīng)用無(wú)關(guān)。
5、觸發(fā)器的一種非常有意義的使用就是創(chuàng)建審計(jì)跟蹤。使用觸發(fā)器,把更改(如果需要,甚至還有之前和之后的狀態(tài))記錄到另外一個(gè)表是非常容易的。
6、MySQL觸發(fā)器不支持call語(yǔ)句,無(wú)法從觸發(fā)器內(nèi)調(diào)用存儲(chǔ)過(guò)程。
?
總結(jié)
以上是生活随笔為你收集整理的关系数据库——视图/存储过程/触发器的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 探索式软件测试
- 下一篇: 关系数据库——关系数据语言