基礎(chǔ)
可以將視圖理解為一個(gè)虛擬表,表中的數(shù)據(jù)就是 SQL 語(yǔ)句從別的表中檢索出來(lái)的尝丐。因此显拜,也可以將視圖理解為對(duì)這些復(fù)雜 SQL 語(yǔ)句的封裝。
使用聯(lián)結(jié)時(shí)爹袁,整個(gè) SQL 語(yǔ)句可能會(huì)寫(xiě)的很長(zhǎng)远荠,非常不利于復(fù)用。利用視圖可一次性編寫(xiě)出基礎(chǔ)的 SQL 語(yǔ)句呢簸,然后根據(jù)需要多次重復(fù)使用矮台。
類似于編程中將某些復(fù)雜功能封裝成函數(shù),然后可以簡(jiǎn)單地調(diào)用根时, 而不需要多次復(fù)制相同的代碼瘦赫。
視圖對(duì)復(fù)雜的 SQL 語(yǔ)句提供了封裝,為復(fù)用提供了便利條件蛤迎;同時(shí)也控件用戶對(duì)表的訪問(wèn)确虱,保護(hù)了表中的數(shù)據(jù)。
視圖是一個(gè)虛擬表替裆,它可以與表一樣使用校辩,如:可以 SELECT,過(guò)濾和排序辆童,也可以聯(lián)結(jié)到其他表或視圖中宜咒,甚至能增加或更新數(shù)據(jù) —— 不過(guò)有一些限制。
視圖本身不包含任何數(shù)據(jù)把鉴,它返回的數(shù)據(jù)都是從其他表中檢索出來(lái)的故黑。在修改原表中的數(shù)據(jù)后,通過(guò)視圖檢索出來(lái)的結(jié)果也會(huì)隨之改變庭砍。
視圖與表一樣场晶,視圖名必須唯一,不能與表名相同怠缸,也不能與其他視圖名相同诗轻。
視圖的數(shù)據(jù)都是動(dòng)態(tài)查詢,所以如果視圖嵌套過(guò)多揭北,性能可能會(huì)嚴(yán)重下降扳炬。
益處
對(duì)復(fù)雜SQL的封裝吏颖,簡(jiǎn)化調(diào)用。
限制對(duì)表的訪問(wèn)鞠柄,保護(hù)表中的數(shù)據(jù)侦高。
更新數(shù)據(jù)格式和表示。視圖在返回?cái)?shù)據(jù)時(shí)厌杜,可以將表中的數(shù)據(jù)進(jìn)行修改奉呛,并將修改后的數(shù)據(jù)返回給調(diào)用者,而不是表中原本的格式夯尽。
創(chuàng)建
創(chuàng)建視圖用 CREATE VIEW+AS 關(guān)鍵字瞧壮。其中 AS 后面跟的是封裝的 SQL 語(yǔ)句。
SELECT Customers.cust_id,cust_name,cust_email,Orders.[order_num]
FROM Customers,OrderItems,Orders
WHERE OrderItems.[prod_id]= 'BNBG01'
AND Orders.[order_num]=OrderItems.[order_num]
AND Orders.[cust_id]=Customers.[cust_id]
上述是查詢所有定了 BNBG01 產(chǎn)品的用戶的 cust_id , cust_name , cust_email 以及對(duì)應(yīng)的訂單號(hào)匙握。
如果查詢定過(guò) RGAN01 產(chǎn)品的用戶的信息咆槽,就需要將一堆的聯(lián)結(jié)查詢重新復(fù)制一遍,然后重新運(yùn)行圈纺。
在寫(xiě)程序中秦忿,如此重復(fù)的復(fù)雜的代碼肯定是需要進(jìn)行抽取成單獨(dú)的函數(shù)的,在 sql 中也一樣:它會(huì)將其中共性的部分抽取成視圖蛾娶,而非共性的部分就類似于傳入函數(shù)中的參數(shù)灯谣。如:
CREATE VIEW HasOrderCust AS
SELECT Customers.cust_id,cust_name,Orders.[order_num],OrderItems.[prod_id]
FROM Customers,OrderItems,Orders
WHERE Orders.[order_num]=OrderItems.[order_num]
AND Orders.[cust_id]=Customers.[cust_id];
通過(guò) CREATE VIEW+AS 創(chuàng)建了一個(gè)名為 HasOrderCust 的視圖。SELECT 語(yǔ)句定義了這個(gè)視圖中的數(shù)據(jù)來(lái)源:所有有訂單的顧客的 cust_id , cust_name 以及對(duì)應(yīng)的訂單號(hào)蛔琅,prod_id胎许。
這里將最上面的聯(lián)結(jié)查詢中的公共部分給抽取出來(lái)的 —— 視圖中包含了所有有訂單的客戶,想查詢具體定了某個(gè)產(chǎn)品的客戶罗售,直接從該視圖中查詢即可辜窑。這里的具體產(chǎn)品就是要傳入視圖中的參數(shù)。
使用該視圖如下:
SELECT * FROM HasOrderCust WHERE prod_id=‘BR03’;
這里 WHERE 中用到了 prod_id寨躁,因此視圖中必須返回 OrderItems.prod_id穆碎,不然視圖中沒(méi)有該列,WHERE 子句便無(wú)法執(zhí)行职恳。
在執(zhí)行時(shí)惨远,會(huì)將指定的 WHERE 子句添加到視圖中已有的 WHERE 子句中,以便查詢出正確的數(shù)據(jù)话肖。簡(jiǎn)單理解:WHERE 會(huì)從視圖(此時(shí)將視圖當(dāng)作一個(gè)表)中查詢出滿足 WHERE 條件的數(shù)據(jù)。
會(huì)被當(dāng)作條件的列葡幸,必須在視圖中存在 —— 比如上面的 prod_id —— 否則執(zhí)行時(shí)便會(huì)報(bào)錯(cuò)最筒。
這也說(shuō)明了視圖是可以控制外界對(duì)表中數(shù)據(jù)的訪問(wèn)的,比如沒(méi)有 prod_id 列則外界便無(wú)法使用該列蔚叨。
刪除視圖
使用DROP VIEW即可床蜘。
如:
DROP VIEW HasOrderCust;
格式化數(shù)據(jù)
CREATE VIEW T AS
SELECT cust_address||'('||cust_name||')' AS fullname
FROM Customers; -- 創(chuàng)建視圖辙培,同時(shí)格式化視圖返回的數(shù)據(jù)
SELECT * FROM T; -- 從視圖中查詢數(shù)據(jù)
在創(chuàng)建視圖時(shí)對(duì)檢索到的數(shù)據(jù)進(jìn)行格式化,所以通過(guò) SELECT * FROM T 進(jìn)行查詢時(shí)只能得到格式化后的數(shù)據(jù)邢锯,得不到 Customers 表中存儲(chǔ)的原始數(shù)據(jù)扬蕊。這也是視圖保護(hù)表中數(shù)據(jù)的一個(gè)體現(xiàn)。
如果需要多次調(diào)用視圖中格式化后的數(shù)據(jù)丹擎,則會(huì)非常簡(jiǎn)便尾抑,不需要每一次都寫(xiě)列名拼接。
過(guò)濾
CREATE VIEW T AS
SELECT cust_email AS fullname
FROM Customers WHERE cust_email IS NOT NULL;
該語(yǔ)句會(huì)將所有值不是 null 的 cust_email 組成一個(gè)視圖蒂培。
計(jì)算字段
CREATE VIEW TotalPrice AS
SELECT order_num,quantity,item_price,quantity*item_price AS total
FROM OrderItems; -- 定義視圖
SELECT sum(total),order_num FROM TotalPrice GROUP BY order_num;
第一步創(chuàng)建視圖再愈,并在創(chuàng)建時(shí)為視圖指定了 total 列:該列的值由計(jì)算得到。