1視圖
視圖是虛擬的表。與包含數據的表不一樣,視圖只包含使用動態檢索數據的查詢。
用實例說話:
輸入
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 = 'RGAN01';
輸出
+---------------+--------------------+
| cust_name | cust_contact |
+---------------+--------------------+
| Fun4All | Denise L. Stephens |
| The Toy Store | Kim Howard |
+---------------+--------------------+
此查詢用來檢索訂購了某種產品的顧客。任何需要這個數據的人都必須理解相關表的結構,知道如何創建查詢和對標的聯結。
現在,假如可以把整個查詢包裝成一個名爲ProductCustomers的虛擬表,則可以如下輕鬆地檢索出相同的數據:
SELECT cust_name, cust_contact
FROM ProductCustomers
WHERE prod_id = 'RGAN01';
這就是視圖的作用。ProductCustomers是一個視圖,作爲一個視圖,它不包含任何列和數據,包含的是一個查詢(與上面用以正確連接表的相同查詢)。
當然現在我們還沒有創建ProductCustomers視圖,是檢索不出來的,所以會報如下錯誤:
ERROR 1146 (42S02): Table 'data.productcustomers' doesn't exist
1.1爲什麼使用視圖呢?
下面是視圖的一些常用應用
- 重用SQL語句。
- 簡化複雜的SQL操作。在編寫查詢後,可以方便的重用它而不必知道其基本的查詢細節。
- 使用表的一部分而不是整個表。
- 保護數據。可以授予用戶訪問表的特定部分的權限,而不是整個標的訪問權限。
- 更改 數據格式和表示。視圖可以返回與底層表的表示和格式不同的數據。
創建視圖後,可以用與表基本相同的方式使用它們。可以對視圖執行SELECT操作,過濾和排序數據,將視圖聯結到其他表或者視圖,甚至添加和更新數據(添加和更新數據存在某些限制。關於這個內容稍後還要做進一步的介紹)。
視圖本身不包含數據,因此它們返回的數據是從其他表中檢索出來的。在添加或更改這些表中的數據時,視圖將返回改變過的數據。
1.2視圖的規則和限制
- 與表一樣,視圖必須唯一命名(不能給視圖取和別的視圖或者表相同的名字)。
- 對於可創建的視圖數目沒有限制。
- 爲了創建視圖,必須有足夠的訪問權限。這些限制通常由數據局管理人員授予。
- 視圖可以嵌套,即可以利用其它視圖中檢索數據的查詢來構造一個視圖。
- ORDER BY可以用在視圖中,但如果從該視圖檢索數據SELECT中含有ORDER BY,那麼該視圖中的ORDER BY 將被覆蓋。
- 視圖不能索引,也不能有關聯的觸發器或默認值。
- 視圖可以和表一起使用。例如:編寫一條聯結表和視圖的SELECT語句。
- 有些DBMS要求返回所有列進行命名,如果列式計算字段,則需要使用別名。
- 有些DBMS把視圖作爲只讀的查詢,這表示可以從視圖中查詢數據,但不能將數據寫回底層表。
- 有些DBMS允許創建這樣的視圖,它不能進行導致行不再屬於視圖的插入或更新。
2使用視圖
視圖的創建
- 視圖用CREATE VIEW語句來創建。
- 使用SHOW CREATE VIEW viewname;來查看創建視圖的語句。
- 用DROP刪除視圖,其語法爲DROP VIEW viewname;。
- 更新視圖時,可以先用DROP再用CREATE,也可以直接用CREATE OR REPLACE VIEW。如果要更新的視圖不存在,則第2條更新語句會創建一個視圖,如果要更新的視圖存在,則第2條更新語句會替換原有的視圖。
2.1利用視圖簡化複雜的聯結
輸入
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;
使用 show create view ProductCustomers; 查看視圖
mysql> show create view ProductCustomers;
+------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+----------------------+
| View | Create View | character_set_client | collation_connection |
+------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+----------------------+
| productcustomers | CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `productcustomers` AS select `customers`.`cust_name` AS `cust_name`,`customers`.`cust_contact` AS `cust_contact`,`orderitems`.`prod_id` AS `prod_id` from ((`customers` join `orders`) join `orderitems`) where ((`customers`.`cust_id` = `orders`.`cust_id`) and (`orderitems`.`order_num` = `orders`.`order_num`)) | gbk | gbk_chinese_ci |
+------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+----------------------+
分析:這條語句創建一個名爲productcustomers的視圖,它聯結三個表,以返回已訂購了任意產品的所有客戶的列表。如果執行SELECT * FROM productcustomers,將列出訂購了任意產品的客戶。
接下來檢索訂購了產品RGAN01的顧客,可如下進行:
SELECT cust_name, cust_contact
FROM ProductCustomers
WHERE prod_id = 'RGAN01';
+---------------+--------------------+
| cust_name | cust_contact |
+---------------+--------------------+
| Fun4All | Denise L. Stephens |
| The Toy Store | Kim Howard |
+---------------+--------------------+
分析:這條語句通過WHERE子句從視圖中檢索特定數據。當DBMS處理此查詢時,它將指定的WHERE子句添加到視圖查詢中已有的WHERE子句中,以便正確過濾數據。
可以看出,視圖極大地簡化了複雜SQL語句的使用。利用視圖,可一次性編寫基礎的SQL,然後根據需要多次使用。
2.2用視圖重新格式化檢索出的數據
視圖的另一常見用途是重新格式化檢索出的數據。下面的SELECT語句(來自第10章)在單個組合計算列中返回供應商名和位置:
SELECT Concat(RTrim(vend_name), '(',RTRIM(vend_country),')')
AS vend_title
FROM Vendors
ORDER BY vend_name;
+------------------------+
| vend_title |
+------------------------+
| Bear Emporium(USA) |
| Bears R Us(USA) |
| Doll House Inc.(USA) |
| Fun and Games(England) |
| Furball Inc.(USA) |
| Jouets et ours(France) |
+------------------------+
把此語句轉換爲一個視圖,如下所示
CREATE VIEW VendorLocations AS
SELECT Concat(RTrim(vend_name), '(',RTRIM(vend_country),')')
AS vend_title
FROM Vendors
ORDER BY vend_name;
查看視圖VendorLocations
mysql> show create view VendorLocations;
+-----------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+----------------------+
| View | Create View | character_set_client | collation_connection |
+-----------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+----------------------+
| vendorlocations | CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `vendorlocations` AS select concat(rtrim(`vendors`.`vend_name`),'(',rtrim(`vendors`.`vend_country`),')') AS `vend_title` from `vendors` order by `vendors`.`vend_name` | gbk | gbk_chinese_ci |
+-----------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+----------------------+
分析:這條語句使用與以前的SELECT語句相同的查詢創建視圖。爲了檢索出以創建所有郵件標籤的數據,可如下進行:
SELECT *
FROM VendorLocations;
+------------------------+
| vend_title |
+------------------------+
| Bear Emporium(USA) |
| Bears R Us(USA) |
| Doll House Inc.(USA) |
| Fun and Games(England) |
| Furball Inc.(USA) |
| Jouets et ours(France) |
+------------------------+
2.3用視圖過濾不想要的東西
視圖對於應用普通的WHERE子句也很有用。例如,可以定義customeremaillist視圖,它過濾沒有電子郵件地址的客戶。爲此目的,可使用下面的語句:
CREATE VIEW CustomerEMailList AS
SELECT cust_id, cust_name, cust_email
FROM Customers
WHERE cust_email IS NOT NULL;
分析:顯然,在發送電子郵件到郵件列表時,需要排除沒有電子郵件地址的用戶。這裏的WHERE子句過濾了cust_email列中具有NULL值的那些行,使他們不被檢索出來。
SELECT *
FROM CustomerEMailList;
+------------+--------------+-----------------------+
| cust_id | cust_name | cust_email |
+------------+--------------+-----------------------+
| 1000000001 | Village Toys | sales@villagetoys.com |
| 1000000003 | Fun4All | jjones@fun4all.com |
| 1000000004 | Fun4All | dstephens@fun4all.com |
+------------+--------------+-----------------------+
2.4使用視圖與計算字段
視圖對於簡化計算字段的使用特別有用。例如檢索某個特定訂單中的物品,計算每種物品的總價格:
SELECT prod_id,
quantity,
item_price,
quantity*item_price AS expanded_price
FROM OrderItems
WHERE order_num = 20008;
+---------+----------+------------+----------------+
| prod_id | quantity | item_price | expanded_price |
+---------+----------+------------+----------------+
| RGAN01 | 5 | 4.99 | 24.95 |
| BR03 | 5 | 11.99 | 59.95 |
| BNBG01 | 10 | 3.49 | 34.90 |
| BNBG02 | 10 | 3.49 | 34.90 |
| BNBG03 | 10 | 3.49 | 34.90 |
+---------+----------+------------+----------------+
要將其轉換爲一個視圖,可以如下進行
CREATE VIEW OrderItemsExpanded AS
SELECT order_num,
prod_id,
quantity,
item_price,
quantity*item_price AS expanded_price
FROM OrderItems;
爲檢索訂單20008的詳細內容(上面的輸出),如下進行
SELECT *
FROM OrderItemsExpanded
WHERE order_num = 20008;
+-----------+---------+----------+------------+----------------+
| order_num | prod_id | quantity | item_price | expanded_price |
+-----------+---------+----------+------------+----------------+
| 20008 | RGAN01 | 5 | 4.99 | 24.95 |
| 20008 | BR03 | 5 | 11.99 | 59.95 |
| 20008 | BNBG01 | 10 | 3.49 | 34.90 |
| 20008 | BNBG02 | 10 | 3.49 | 34.90 |
| 20008 | BNBG03 | 10 | 3.49 | 34.90 |
+-----------+---------+----------+------------+----------------+
這樣下來我們共創建了4個視圖如下:
可以看到視圖非常容易創建,而且也很好用,它將相當於封裝了一些查詢語句在一個你定義的虛擬表中,將正確使用視圖可以大大簡化複雜數據的處理。