mysql提高效率——视图

281 阅读4分钟

1.定义视图

  • 视图是从一个或几个基本表(或视图)导出的表。它与基本表不同,是一个虚表
  • 数据库中只存放视图的定义,而不存放视图对应的数据,这些数据仍存放在原来的基本表中。
  • 视图一经定义,就可以和基本表一样被查询、被删除。也可以在视图之上再定义新的视图。但增删改有一定的限制。

创建语法格式:
CREATE VIEW 视图名称 AS 子查询
实例:创建 sales_by_client 视图
代码如下:

CREATE VIEW sales_by_client AS
SELECT 
	c.client_id,
	c.name,
	SUM(invoice_total) AS total_sales
FROM clients c
JOIN invoices i USING (client_id)
GROUP BY client_id

2.查询视图

  • 视图定义后,用户可以像对基本表一样对视图进行查询
    实例: 查看上方创建视图表的total_sales大于800的姓名
SELECT name
FROM sales_by_client 
WHERE total_sales > 800

3.更新或删除视图

删除视图语法格式:
DREP VIEW 视图名称
实例:删除clients_balance视图
代码如下:

-- 若不存在这个视图,直接 DROP 会报错,所以要加上 IF EXISTS 先检测有没有这个视图
DROP VIEW IF EXISTS clients_balance;
  • 视图作为虚拟表/衍生表,除了可用在查询语句SELECT中,也可以用在增删改(INSERT DELETE UPDATE)语句中,但后者有一定的前提条件。

如果一个视图的原始查询语句中没有如下元素:

  1. DISTINCT 去重
  2. GROUP BY/HAVING/聚合函数 (后两个通常是伴随着 GROUP BY 分组出现的)
  3. UNION 纵向连接

则该视图是可更新视图(Updatable Views),可以增删改,否则只能查。

另外,增(INSERT)还要满足附加条件:视图必须包含底层原表的所有必须字段

总之,一般通过原表修改数据,但当出于安全考虑或其他原因没有某表的直接权限时,可以通过视图来修改底层数据(?) ,前提是视图是可更新的。

实例:创建视图(新虚拟表)invoices_with_balance(带差额的发票记录表)
代码如下:

CREATE OR REPLACE VIEW invoices_with_balance AS
SELECT 
    invoice_id, 
    number, 
    client_id, 
    invoice_total, 
    payment_total, 
    invoice_date,
    invoice_total - payment_total AS balance,  -- 新增列
    due_date, 
    payment_date
FROM invoices
WHERE (invoice_total - payment_total) > 0
/* 这里不能用列别名balance,会报错说不存在,
必须用原列名的表达式,这还是执行顺序的问题
之前讲WHERE和HAVING作为事前筛选和事后筛选的区别时提到过 */

删:删掉id为1的发票记录

DELETE FROM invoices_with_balance
WHERE invoice_id = 1

改:将2号发票记录的期限延后两天

UPDATE invoices_with_balance
SET due_date = DATE_ADD(due_date, INTERVAL 2 DAY)
WHERE invoice_id = 2

增:

  • 在视图中用INSERT新增记录的话还有另一个前提,即视图必须包含其底层所有原始表的所有必须字段
  • 例如,若这个 invoices_with_balance 视图里没有 invoice_date 字段(invoices 中的必须字段),那就无法通过该视图向 invoices 表新增记录,因为 invoices 表不会接受 invoice_date 字段为空的记录

 WITH CHECK OPTION 子句

  • 在视图的原始查询语句最后加上 WITH CHECK OPTION 可以防止执行那些会让视图中某些行(记录)消失的修改语句

实例:接前面的 invoices_with_balance 视图的例子,该视图与原始的 orders 表相比增加了balance(invouce_total - payment_total) 列,且只显示 balance 大于0的行(记录),若将某记录(如2号订单)的 payment_total 改为和 invouce_total 相等,则 balance 为0,该记录会从视图中消失。

UPDATE invoices_with_balance
SET payment_total = invoice_total
WHERE invoice_id = 2

更新后会发现invoices_with_balance视图里2号订单消失。
但在视图原始查询语句最后加入 WITH CHECK OPTION 后,对3号订单执行类似上面的语句后会报错

UPDATE invoices_with_balance
SET payment_total = invoice_total
WHERE invoice_id = 3

-- Error Code: 1369. CHECK OPTION failed 'sql_invoicing.invoices_with_balance'

4.视图的作用

  1. 简化查询
  2. 增加抽象层,减少变化的影响:视图给表增加了一个抽象层(模块化),这样如果数据库设计改变了(如一个字段从一个表转移到了另一个表),只需修改视图的查询语句使其能保持原有查询结果即可,不需要修改使用这个视图的那几十个查询。相反,如果没有视图这一层的话,所有查询将直接使用指向原表的原始查询语句,这样一旦更改原表设计,就要相应地更改所有的这些查询。
  3. 限制对原数据的访问权限:在视图中可以对原表的行和列进行筛选,这样如果你禁止了对原始表的访问权限,用户只能通过视图来修改数据,他们就无法修改视图中未返回的那些字段和记录。但注意这通常并不简单,需要良好的规划,否则最后可能搞得一团乱。