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个视图如下:
可以看到视图非常容易创建,而且也很好用,它将相当于封装了一些查询语句在一个你定义的虚拟表中,将正确使用视图可以大大简化复杂数据的处理。