視圖
視圖是虛擬的表。與包含數據的表不一樣,視圖只包含使用時動態檢索數據的查詢。
理解視圖最好的辦法就是來看一下例子:
SELECT cust_name , cust_contact FROM customers , orders,orderitems WHERE customers.cust_id = orders.cust_id AND orderitems.order_num = orders.order_num AND prod_id = 'TNT2';
結果如下:
+----------------+--------------+
| cust_name | cust_contact |
+----------------+--------------+
| Coyote Inc. | Y Lee |
| Yosemite Place | Y Sam |
+----------------+--------------+
此查詢用來檢索訂購了某個特定產品的客戶。任何需要這個數據的人都必須理解相關表的結構,包括如何創建查詢以及對表的聯結。為了檢索其他的產品的相同數據,必須修改最后的where字句。
現在,加入可以把這個查詢包裝成一個名為productcustomers的虛擬表,測可以如下輕松的檢索出相同的數據:
select cust_name , cust_contact from productcustomers where prod_id = 'TNT2';
這就是視圖的作用,productcustomers是一個視圖,作為視圖,他不包含表中應該用的任何列或數據,他包含的是一個sql查詢(與上面用以正確聯結表的查詢相同的查詢)。
為什么使用視圖
我們看到了視圖的一個例子,下面看一下視圖的常見的應用:
1、重用sql語句
2、簡化復雜的sql操作。在編寫查詢后,可以很方便的重用他,而不必知道他的基本查詢細節。
3、使用表的組成部分而不是整個表。
4、保護數據。可以給用戶授予表的特定部分的訪問權限。
5、更改數據的格式和表示。視圖可返回與底層表的表示與格式不同的數據。
在視圖創建了之后,可以用與表基本相同的方式利用它。可以對視圖進行SELECT操作,過濾與排序數據,將視圖聯結到其他的視圖和表,甚至能添加和更新數據(添加和更新數據需要一定的限制 )。
重要的是知道視圖僅僅是用來查看存儲在別處的數據的一種設施。視圖本身不包含數據。因為他們返回的數據是從其他表中查詢而來。再添加和更改這些表中的數據后,視圖將會返回改變過的數據。
性能注意:因為視圖不包含數據,所以每次使用它時,都必須處理查詢執行時所需的任一個檢索。如果你用多個聯結和過濾創建了復雜的視圖或者嵌套了視圖,可能會發現性能下降的很厲害。因此在部署大量的視圖應用之前,需要對視圖的性能做測試。
視圖的規則和限制
下面是對於視圖的創建和使用的一些最常見的規則與限制:
1、與表一樣視圖必須唯一命名。(不能給視圖取和別的視圖或者是表相同的名字)
2、對於可以創建的視圖個數是沒有限制的。
3、為了創建視圖,必須有足夠的權限,這些權限是有數據庫管理員授予的。
4、視圖可以嵌套,即可以利用從其他視圖中檢索數據的查詢來構建一視圖。
5、ORDER BY可以使用在視圖上,但是如果從該視圖中檢索數據的SELECT中如果也包含ORDER BY 語句,則視圖中的ORDER 將會被覆蓋。
6、視圖不能過索引,也不能有關聯的觸發器或默認值。
7、視圖可以和表一起使用。例如,編寫一條連接視圖與表的SELECT語句。
使用視圖
在理解了什么是視圖之后來看一下視圖的創建。
1、使用CREATE VIEW來創建視圖
2、使用SHOW CREATE VIEW viewname,來查看創建視圖的語句。
3、使用DROP VIEW viewname來刪除視圖。
4、更新視圖的時候可以先用DROP 在用CREATE,也可以直接使用CREATE OR REPLACE VIEW 。如果要更新的視圖不存在,第二種更新的語句將會創建一個視圖。如果更新的視圖存在,則在第二條更新語句使用后將會替換以前的視圖。
利用視圖簡化復雜的聯結
視圖最常見的應用之一就是隱藏復雜的sql。因此通常會涉及到表的聯結。舉例如下:
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;
這條語句創建一個名為productcustomers的視圖,他聯結三個表用以返回已訂購了任意產品的所有客戶的列表。如果執行select * from productcustomers ,將列出訂購了任意產品的客戶。
如果我們要檢索訂購了TNT2,這個產品的客戶,可以使用如下:
SELECT cust_name, cust_contact FROM productcustomers WHERE prod_id = 'TNT2';
通過where子句我們從視圖中檢索特定的數據。在mysql處理此查詢時,他將指定的where子句添加到視圖查詢中已有的where子句中,以便正確過濾數據。
可以看出,視圖極大的簡化了復雜sql語句的使用。利用視圖可一次性編寫基礎的sql,然后根據需要多次使用。
注意可重用的視圖:創建不受特定數據限制的視圖是一種好方法。例如上面創建的視圖,返回生產所有產品的客戶而不是某一個特定產品的客戶(TNT2這個產品的客戶)。擴展視圖的范圍不僅使得視圖可以被重用,而且有更多其他的好處。這樣做我們就不用創建和維護多個類似這樣的視圖了。
用視圖格式化檢索出來的數據
如上所述,視圖的另一種用法就是重新格式化檢索出來的數據。下面的select語句在單個組合計算列中,返回供應商名和位置。
SELECT CONCAT(RTRIM(vend_name),'(',RTRIM(vend_country),')') AS vend_title FROM vendors ORDER BY vend_name;
輸出:
+------------------------+
| vend_title |
+------------------------+
| ACME(USA) |
| Anvils R Us(USA) |
| Furball Inc.(USA) |
| Jet Set(England) |
| Jouets Et Ours(France) |
| LT Supplies(USA) |
+------------------------+
現在假如經常使用這樣格式的結果,不必在每次使用時都要執行一次聯結,我們可以創建一個視圖,每次需要的時候使用就可以了。可按如下方法把前面的語句轉化成為視圖。
CREATE VIEW vendorlocations AS
SELECT CONCAT(RTRIM(vend_name),'(',RTRIM(vend_country),')') AS vend_title FROM vendors ORDER BY vend_name;
上面這條語句使用了和前面一樣的查詢來創建了一個視圖,為了檢索出以創建所有郵件標簽的數據。可如下進行:
SELECT *
FROM vendorlocations;
輸出的就過和上面一樣。
用視圖過濾不想要的數據
視圖對於應用普通的where字句也很有用。例如,可以定義一個customermaillist視圖,他過濾沒有電子郵件地址的客戶。為此我們可以使用下面的語句來創建
CREATE VIEW customermaillist AS
SELECT cust_id, cust_name, cust_email FROM customers WHERE cust_email IS NOT NULL;
顯然在我們要發送電子郵件的時候,我們需要排除那些沒有電子郵件的客戶。這里的where子句過濾了cust_mail為null的情況,是他們不能被檢索出來。
現在可以像其他的視圖一樣來使用了。
SELECT *
FROM customermaillist;
結果如下:
+---------+----------------+---------------------+
| cust_id | cust_name | cust_email |
+---------+----------------+---------------------+
| 10001 | Coyote Inc. | ylee@coyote.com |
| 10003 | Wascals | rabbit@wascally.com |
| 10004 | Yosemite Place | sam@yosemite.com |
+---------+----------------+---------------------+
WHERE子句與WHERE 子句 如果從視圖檢索數據時使用了一條WHERE子句,則兩組子句(一組在視圖中,另一組是傳遞給視圖的)將自動組合。
使用視圖與計算字段
視圖對於簡化計算字段的使用特別有用。下面是第 10章中介紹的一條SELECT語句。它檢索某個特定訂單中的物品,計算這種物品的總價格:
SELECT prod_id, quantity, item_price,quantity * item_price AS total_price FROM orderitems WHERE order_num = 20005;
結果為:
+---------+----------+------------+-------------+
| prod_id | quantity | item_price | total_price |
+---------+----------+------------+-------------+
| ANV01 | 10 | 5.99 | 59.90 |
| ANV02 | 3 | 9.99 | 29.97 |
| TNT2 | 5 | 10.00 | 50.00 |
| FB | 1 | 10.00 | 10.00 |
+---------+----------+------------+-------------+
為將其轉換為視圖,可以如下進行
CREATE VIEW orderitemsexpands AS
SELECT prod_id, quantity, item_price,quantity * item_price AS total_price FROM orderitems
這樣我們就可以通過視圖來檢索order_num = 20005;的數據了。如下:
select *
from orderitemsexpands where order_num = 20005;
從上面的這么多用法,我們知道視圖其實是很容易創建,而且很好用。正確的使用它,可以極大的簡化復雜的數據處理。
更新視圖
迄今為止的所有視圖都是和 SELECT語句使用的。然而,視圖的數據能否更新?答案視情況而定。
通常,視圖是可更新的(即,可以對它們使用 INSERT、UPDATE 和DELETE)。更新一個視圖將更新其基表(可以回憶一下,視圖本身沒有數據)。如果你對視圖增加或刪除行,實際上是對其基表增加或刪除行。但是,並非所有視圖都是可更新的。基本上可以說,如果 MySQL不能正確地確定被更新的基數據,則不允許更新(包括插入和刪除)。這實際上意味着,如果視圖定義中有以下操作,則不能進行視圖的更新:
1、 分組(使用GROUP BY和 HAVING);
2、 聯結;
3、 子查詢;
4、並;
5、聚集函數(Min()、 Count()、Sum() 等);
6、 DISTINCT;
7、 導出(計算)列。
換句話說,本章許多例子中的視圖都是不可更新的。這聽上去好像是一個嚴重的限制,但實際上不是,因為視圖主要用於數據檢索。
注意:上面列出的限制自 MySQL 5以來是正確的。不過,未來的 MySQL很可能會取消某些限制。
一般,應該將視圖用於檢索( SELECT語句)而不用於更新( INSERT、UPDATE 和DELETE)。
小結
視圖為虛擬的表。它們包含的不是數據而是根據需要檢索數據的查詢。視圖提供了一種 MySQL的SELECT 語句層次的封裝,可用來簡化數據處理以及重新格式化基礎數據或保護基礎數據。