视图是虚拟的表
与包含数据的表不同,视图只包含使用时动态检索数据的查询
如下代码,该查询用来检索订购了某种产品的顾客,任何需要这个数据的人都必须理解相关表的结构,知道如何创建查询和对表进行联结,检索其他产品(或多个产品)的相同数据,必须修改最后的 WHERE
子句
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 = 'ANV01';
现在,假如可以把整个查询包装成一个名为 ProductCustomers
的虚拟表,则可以如下轻松地检索出相同的数据
SELECT cust_name, cust_contact
FROM ProductCustomers
WHERE prod_id = 'ANV01';
这就是视图的作用,ProductCustomers
是一个视图
作为视图,它不包括任何列或数据,包含的是一个查询(与上面用以正确连接表的相同的查询)
上述代码是使用视图的一个例子,但是视图还有其他的作用
创建视图之后,可以用与表基本相同的方式使用它们
可以对视图执行 SELECT
操作,过滤和排序数据,将视图联结到其他视图或表,甚至添加和更新数据(存在某些限制)
视图仅仅是用来查看存储在别处数据的一种设施
视图本身并不包含数据,因此返回的数据是从其他的表中检索出来的
在添加或更改这些表中数据时,视图将会返回改变过的数据
性能问题:
因为视图不包含数据,所以每次使用视图时,都必须处理查询执行时需要的所有检索
如果使用了多个联结和过滤创建了复杂的视图或者嵌套了视图,性能可能会下降得很厉害
视图创建和使用的一些常见规则和限制:
与表一样,视图必须是唯一命名(不能给视图取与别的视图或表相同的名字)
对可以创建的视图数目没有限制
创建视图,必须具有足够的访问权限,这些权限通常需要数据库管理人员授予
视图可以嵌套,即可以利用从其他视图中检索数据的查询来构造视图;所允许的嵌套层数在不同的 DBMS 中有所不同
在 MySQL 中,可以在视图查询中使用 ORDER BY
子句;但是如果从该视图检索数据 SELECT
中也有 ORDER BY
,那么该视图如中的 ORDER BY
将会被覆盖
视图不能索引,也不能有关联的触发器或默认值
视图可以和表一起使用
视图可以使用 CREATE VIEW
语句来创建
CREATE VIEW
只能创建不存在的视图
使用 SHOW CREATE VIEW viewname;
可以查看创建视图的语句
使用 DROP
删除视图,DROP VIEW viewname;
覆盖(或者更新)视图,必须先删除它,然后再重新创建,先使用 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
, 将列出订购了任意产品的顾客
也可以检索订购了特定产品 ANV01 的顾客
代码如下:
SELECT cust_name, cust_contact
FROM ProductCustomers
WHERE prod_id = 'ANV01';
这条语句通过 WHERE
子句从视图中检索特定数据,当 DBMS 处理此查询时,它将指定的 WHERE
子句添加到视图查询中已有的 WHERE
子句中,以便正确过滤数据
可以看出,视图可以极大地简化复杂大的 SQL 语句的使用
利用视图,可以一次性编写基础的 SQL 语句,然后根据需要多次使用
创建可重用的视图:
创建不绑定特定数据的视图是一个好方法
上述例子中的视图返回订购所有产品而不仅仅是 ANV01 的顾客
扩展视图的范围不仅使得它能够被重用,而且可能更有用,这样可以避免创建和维护多个类似的视图
视图的另一种常见用途是重新格式化检索出的数据
如下代码示例,使用 SELECT
语句在单个组合 计算列 中返回供应商的名字和位置
SELECT Concat(vend_name, ' ( ', vend_country, ' ) ')
AS vend_title
FROM Vendors
ORDER BY vend_name;
现在,假设经常需要这个格式的结果,我们不必在每次需要时执行这种拼接,而是创建一个视图,使用它即可
将上述语句转化为视图,如下代码所示:
CREATE VIEW VendorLocations AS
SELECT Concat(vend_name, ' ( ', vend_country, ' ) ')
AS vend_title
FROM Vendors;
使用上述视图,如下所示:
SELECT * FROM VendorLocations;
视图对于应用普通的 WHERE
子句也很有用
例如,可以定义 Customer Email List 视图,过滤没有电子邮件地址的顾客
CREATE VIEW CustomerEmailList AS
SELECT cust_id, cust_name, cust_email
FROM Customers
WHERE cust_email IS NOT NULL;
SELECT * FROM CustomerEmailList;
SELECT cust_id, cust_name, cust_email
FROM CustomerEmailList
WHERE cust_name = 'Wascals';
从视图检索数据时,如果使用了一条 WHERE
子句,则两组子句(一组在视图中,一组传递给视图的)将自动结合
在简化计算字段的使用上,视图也特别有用
如下代码示例,是 计算字段 中使用过的,检索某个订单中的物品,计算每种物品的总价格
SELECT prod_id, quantity, item_price,
quantity*item_price AS expanded_price
FROM OrderItems
WHERE order_num = 20009;
要将其转化为一个视图
CREATE VIEW OrderItemsExpanded AS
SELECT order_num, prod_id, quantity, item_price,
quantity*item_price AS expanded_price
FROM OrderItems;
使用视图
SELECT * FROM OrderItemsExpanded
WHERE order_num = 20009;
视图是可以更新的(即,可以对它们使用 INSERT
、UPDATE
、DELETE
)
更新一个视图将更新其基表;如果对视图增加或者删除行,实际上是对其基表增加或者删除行
并非所有视图都是可更新的
如果 MySQL 不能正确地确定被更新的基数据,则不允许更新(包括插入和删除)
即,如果视图定义中有以下操作,则不能进行视图的更新:
GROUP BY
和 HAVING
)DISTINCT
SELECT
语句的层次,可以用来简化数据处理,重新格式化或保护基础数据