VIEW. 视图

1. 创建视图

Creating Views (5:36)

小结

就是创建虚拟表,自动化一些重复性的查询模块,简化各种复杂操作(包括复杂的子查询和连接等)

注意视图虽然可以像一张表一样进行各种操作,但并没有真正储存数据,数据仍然储存在原始表中,视图只是储存起来的模块化的查询结果,是为了方便和简化后续进一步操作而储存起来的虚拟表。

 创建 sales_by_client 视图

USE sql_invoicing;

CREATE VIEW sales_by_client AS
    SELECT 
        client_id,
        name,
        SUM(invoice_total) AS total_sales
    FROM clients c
    JOIN invoices i USING(client_id)
    GROUP BY client_id, name;
    -- 虽然实际上这里加不加上name都一样

若要删掉该视图用 DROP VIEW sales_by_client 或通过右键菜单

创建视图后可就当作 sql_invoicing 库下一张表一样进行各种操作

USE sql_invoicing;

SELECT 
    s.name,
    s.total_sales,
    phone
FROM sales_by_client s
JOIN clients c USING(client_id)
WHERE s.total_sales > 500

练习

创建一个客户差额表视图,可以看到客户的id,名字以及差额(发票总额-支付总额)

USE sql_invoicing;

CREATE VIEW clients_balance AS
    SELECT 
        client_id,
        c.name,
        SUM(invoice_total - payment_total) AS balance
    FROM clients c
    JOIN invoices USING(client_id)
    GROUP BY client_id

2. 更新或删除视图

小结

修改视图可以先DROP在CREATE(也可以用CREATE OR REPLACE)

视图的查询语句可以在编辑模式下查看和修改,但最好是保存为sql文件并放在源码控制妥善管理

案例

想在上一节的顾客差额视图的查询语句最后加上按差额降序排列

法1. 先删除再重建

USE sql_invoicing;

DROP VIEW IF EXISTS clients_balance;
-- 若不存在这个视图,直接 DROP 会报错,所以要加上 IF EXISTS 先检测有没有这个视图

CREATE VIEW clients_balance AS 
    ……
    ORDER BY balance DESC

法2. 用REPLACE关键字,即用 CREATE OR REPLACE VIEW clients_balance AS,和上面等效,不过上面那种分成两个语句的方式要用的多一点

USE sql_invoicing;

CREATE OR REPLACE VIEW clients_balance AS
    ……
    ORDER BY balance DESC

方法

如何保存视图的原始查询语句?

法1.

(推荐方法) 将原始查询语句保存为 views 文件夹下的和与视图同名的 clients_balance.sql 文件,然后将这个文件夹放在源码控制下(put these files under source control), 通常放在 git repository(仓库)里与其它人共享,团队其他人因此能在自己的电脑上重建这个数据库

法2.

若丢失了原始查询语句,要修改的话可点击视图的扳手按钮打开编辑模式,可看到如下被MySQL处理了的查询语句

MySQL在前面加了些莫名其妙的东西并且在所有库名表名字段名外套上反引号防止名称冲突(当对象名和MySQL里的关键字相同时确保被当作对象名而不是关键字),但这都不影响

直接做我们需要的修改,如加上ORDER BY balance DESC 然后点apply就行了

CREATE 
    ALGORITHM = UNDEFINED 
    DEFINER = `root`@`localhost` 
    SQL SECURITY DEFINER
VIEW `clients_balance` AS
    SELECT 
        `c`.`client_id` AS `client_id`,
        `c`.`name` AS `name`,
        SUM((`invoices`.`invoice_total` - `invoices`.`payment_total`)) AS `balance`
    FROM
        (`clients` `c`
        JOIN `invoices` ON ((`c`.`client_id` = `invoices`.`client_id`)))
    GROUP BY `c`.`client_id`
    ORDER BY balance DESC

3. 可更新视图

小结

视图作为虚拟表/衍生表,除了可用在查询语句SELECT中,也可以用在增删改(INSERT DELETE UPDATE)语句中,但后者有一定的前提条件。

如果一个视图的原始查询语句中没有如下元素:
1. DISTINCT 去重
2. GROUP BY/HAVING/聚合函数 (后两个通常是伴随着 GROUP BY 分组出现的)
3. UNION 纵向连接

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

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

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

之后会将关于安全和权限的内容

案例

创建视图(新虚拟表)invoices_with_balance(带差额的发票记录表)

USE sql_invoicing;

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作为事前筛选和事后筛选的区别时提到过 */
  1. 删:

删掉id为1的发票记录

DELETE FROM invoices_with_balance
WHERE invoice_id = 1

2.改

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

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

3.增

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

你可能感兴趣的:(数据库)