欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

MySQL可更新视图操作教程

程序员文章站 2022-07-01 18:28:27
可更新视图是指通过视图,来更新、插入、删除基本表中的数据。视图是一个虚拟表,即对视图的更新,实质上是更新基表。但是视图的构造很多时候是由多个表连接查询,以及结合聚合函数,分组过滤等等定义的。对于这类...

可更新视图是指通过视图,来更新、插入、删除基本表中的数据。视图是一个虚拟表,即对视图的更新,实质上是更新基表。但是视图的构造很多时候是由多个表连接查询,以及结合聚合函数,分组过滤等等定义的。对于这类的视图,想要去更新,恐怕就显得力不从心了。因为涉及到多张表。本文简要描述可更新视图的特点并给出演示。

一、不带check option更新

-- 当前环境
mysql> show variables like 'version';
+---------------+--------+
| variable_name | value |
+---------------+--------+
| version | 5.7.17 |
+---------------+--------+
-- 可更新视图演示

drop table if exists items;

create table items
(
   id int auto_increment primary key,
   name varchar(100) not null,
   price decimal(11, 2) not null
);

-- 为items表填充数据

insert into items(name, price)
values ('laptop', 700.56), ('desktop', 699.99), ('ipad', 700.50);

create or replace view vw_items
as
   select *
   from items
   where price > 700;

-- 查询视图

select * from vw_items;

-- 以下语句插入成功,基表和视图同时可见

insert into vw_items
values (null, 'iphone', 800.50);

-- 以下语句插入成功,基表可见,因为视图包含了where子句对其过滤

insert into vw_items
values (null, 'iphone4', 500.50);

-- query ok, 1 row affected (0.00 sec)

select * from vw_items;

二、基于check option更新

-- 先清空一下数据

truncate table items;

create or replace view vw_items_check
as
   select *
   from items
   where price > 700
   with check option;

-- 下面基于vw_items_check创建另外一个视图vw_items_check2
create or replace view vw_items_check2
as
   select *
   from vw_items_check
   where price < 1000
   with local check option;

-- 下面基于vw_items_check创建另外一个视图vw_items_check3
create or replace view vw_items_check3
as
   select *
   from vw_items_check
   where price < 1000
   with cascaded check option;

-- 基于视图vw_items_check插入数据,以下语句插入失败,不符合视图过滤条件
insert into vw_items_check
values (null, 'laptop', 600.56);

-- error 1369 (hy000): check option failed 'sakila.vw_items_check'

-- 基于视图vw_items_check插入数据,以下语句执行成功
-- 满足where子句过滤条件,插入后基表和视图数据可见
insert into vw_items_check
values (null, 'laptop', 700.56);

-- 基于视图vw_items_check2插入数据成功,值符合过滤条件
insert into vw_items_check2
values (null, 'iphone', 800.50);

-- 基于视图vw_items_check3插入数据成功,值符合过滤条件
insert into vw_items_check3
values (null, 'iphone3', 800.50);

-- 下面使用一个不符合预期的值进行插入
-- 基于视图vw_items_check2插入数据失败,值不符合底层过滤条件
insert into vw_items_check2
values (null, 'iphone_chk2', 700);

-- error 1369 (hy000): check option failed 'sakila.vw_items_check2'

-- 基于视图vw_items_check3插入数据失败,值不符合底层过滤条件
insert into vw_items_check3
values (null, 'iphone_chk2', 700);

-- error 1369 (hy000): check option failed 'sakila.vw_items_check3'

-- 通过上面的测试发现,使用cascaded与local创建的视图都会检查底层依赖
-- 在此并无特别
-- 说明5.7.6版本以前,视图vw_items_check2不符合底层预期时,也可以成功执行

三、进一步测试对比cascaded与local

-- 再次创建如下视图,此时的视图底层基于非check视图

create or replace view vw_items_check4
as
   select *
   from vw_items
   where price < 1000
   with local check option;

create or replace view vw_items_check5
as
   select *
   from vw_items
   where price < 1000
   with cascaded check option;

-- 基于视图vw_items_check4插入数据成功,值不符合底层过滤条件
-- 但是此时可以成功插入,说明local生效,不依赖底层过滤条件    
insert into vw_items_check4
values (null, 'iphone_chk4', 700);    

query ok, 1 row affected (0.00 sec)

-- 下面验证插入结果,查询vw_items_check4被过滤
select * from vw_items_check4;
+----+---------+--------+
| id | name | price |
+----+---------+--------+
| 1 | laptop | 700.56 |
| 2 | iphone | 800.50 |
| 3 | iphone3 | 800.50 |
+----+---------+--------+

-- 查询基表数据存在
select * from items;
+----+-------------+--------+
| id | name | price |
+----+-------------+--------+
| 1 | laptop | 700.56 |
| 2 | iphone | 800.50 |
| 3 | iphone3 | 800.50 |
| 4 | iphone_chk4 | 700.00 |
+----+-------------+--------+

-- 基于视图vw_items_check5插入数据失败,cascade级联校验生效
insert into vw_items_check5
values (null, 'iphone_chk5', 700);

-- error 1369 (hy000): check option failed 'sakila.vw_items_check5'

四、基于视图删除

-- 基于视图vw_items_check4删除数据
-- 如下,提示删除成功,但基表数据未删除,因为不满足过滤条件
delete from vw_items_check4
where id = 4;

-- query ok, 0 rows affected (0.00 sec)

-- author : leshami
-- blog : https://blog.csdn.net/leshami

-- 基于视图vw_items_check5删除数据
-- 如下,提示删除成功,但基表数据未删除,因为不满足过滤条件
delete from vw_items_check5
where id = 4;

-- query ok, 0 rows affected (0.00 sec)

-- 满足过滤条件 id为3的记录能够被删除
delete from vw_items_check5
where id = 3;

-- query ok, 1 row affected (0.00 sec)

-- 删除后的结果
select * from items;
+----+-------------+--------+
| id | name | price |
+----+-------------+--------+
| 1 | laptop | 700.56 |
| 2 | iphone | 800.50 |
| 4 | iphone_chk4 | 700.00 |
+----+-------------+--------+

五、更新视图

-- 由于不符合过滤条件,2个视图均无法更新
update vw_items_check5
set price = 701
where id = 4;    

query ok, 0 rows affected (0.00 sec)
rows matched: 0 changed: 0 warnings: 0

update vw_items_check4
set price = 701
where id = 4;   

query ok, 0 rows affected (0.00 sec)
rows matched: 0 changed: 0 warnings: 0

-- 基于视图vw_items5更新数据,此时选择满足条件的记录来更新
-- 更新为比过滤条件低的价格,无法成功更新
update vw_items_check5
set price = 700
where id = 2; 

error 1369 (hy000): check option failed 'sakila.vw_items_check5'

-- 更新为符合条件时,被成功更新
update vw_items_check5
set price = 900
where id = 2;

query ok, 1 row affected (0.00 sec)
rows matched: 1 changed: 1 warnings: 0

六、cascade 与local的差异(官方描述)

-- 未指定local与cascade时,缺省为cascade
-- 官方给出的关于local与cascaded对比
/*

 with local, the view where clause is checked, then checking recurses to underlying views and
applies the same rules.

 with cascaded, the view where clause is checked, then checking recurses to underlying views,
adds with cascaded check option to them (for purposes of the check; their definitions remain
unchanged), and applies the same rules.

 with no check option, the view where clause is not checked, then checking recurses to underlying
views, and applies the same rules.
*/

七、结论:

1、不使用check子句情形,可以对视图进行dml操作,影响基表数据

2、使用check子句情形,所有的dml必须满足过滤条件,否则报错,update语句更新后的值不符合过滤条件则无法更新

3、local与cascaded选项受底层视图影响,如果底层视图带check,则两者作用相同,否则local进作用于当前