12. 视图

2018-02-07  本文已影响0人  shark_tear

视图在数据库中是一张虚拟表,表中的字段由自己定义或者来自其他数据库。表中的数据可以来自单张表、单表中若干个字段,还可以来自多个表、函数等。主要取决于视图定义命令里的查询语句。

视图的作用

  1. 加速查询,在查询语句特别复杂的时候,查询花费的时间很大概率会变长,而如果将查询语句的结果定义成一个视图,下次就可以直接通过查询视图来查询所需的数据,效率会更高。
  2. 隐藏某些加密字段,比如隐藏用户表的密码、联系方式等信息

视图的分类

  1. 普通视图,正常功能的视图,会一直保存在模式里。查询数据时从原来的表查询;
  2. 临时视图,数据从表中查询,数据库连接断开时,视图消失;
  3. 物化视图,用创建的时候表中查询到的数据创建的时候,可以更新。数据查询的时候直接查视图,不查原来的表。

视图的定义

命令格式如下所示:

CREATE [OR REPLACE] [TEMP | TEMPORARY ] [MATERIALIZED] VIEW view_name (field1, field2....) 
AS query
[ WITH [ CASCADED | LOCAL ] CHECK OPTION ]

示例如下
示例1 先创建一个信息表,然后在信息表上创建一个临时视图

postgres=# create table info(id int, email text, phone text, address text);
CREATE TABLE
postgres=# create temp view vw_info (id, phone) as select id, phone from info;
CREATE VIEW

# 显示视图信息
postgres=# \d vw_info; 
   View "pg_temp_2.vw_info"
 Column |  Type   | Modifiers 
--------+---------+-----------
 id     | integer | 
 phone  | text    | 

postgres=# \d 
            List of relations
  Schema   |   Name    | Type  |  Owner   
-----------+-----------+-------+----------
 pg_temp_2 | vw_info   | view  | postgres

上面的视图vw_info,里面只保存了info信息表的id和phone字段,其他字段都被隐藏。在vw_info 视图名后面的括号里定义视图的字段id和phone。而且vw_info还是一个临时视图,我们退出后登录,结果如下所示:

postgres=# \q
-bash-4.2$ psql 
Password: 
psql (9.6.6)
Type "help" for help.

postgres=# \d
           List of relations
 Schema |   Name    | Type  |  Owner   
--------+-----------+-------+----------

可以看到vw_info这个视图已经消失了。

示例2:定义一个vw_info2视图,只需要info里的id和email字段,但是使用新的名称。

postgres=# create view vw_info2 (user_id, user_email) as select id, email from info;
CREATE VIEW

postgres=# \d vw_info2
      View "public.vw_info2"
   Column   |  Type   | Modifiers 
------------+---------+-----------
 user_id    | integer | 
 user_email | text    | 

从上面可以看到vw_info2视图中的字段名是新定义的字段名。往表info里面插入几个值,然后再看视图vw_info2视图里的值。

postgres=# insert into info values(1, 'alias@linux.com', '1234-234', 'NewYork');
INSERT 0 1
postgres=# insert into info values(2, 'Bob@gmail.com', '3444-235', 'WashingTon');
INSERT 0 1
postgres=# select id,email from info; 
 id |      email      
----+-----------------
  1 | alias@linux.com
  2 | Bob@gmail.com
(2 rows)

postgres=# select * from vw_info2; 
 user_id |   user_email    
---------+-----------------
       1 | alias@linux.com
       2 | Bob@gmail.com
(2 rows)

可以看到,两者中的值是一致的。

示例3:物化视图,创建一个物化vw_info3,查看视图里的数据,然后往表里插入一条新数据,再查看视图。

postgres=# create materialized view vw_info3 as select id, name from triggerdb; 
SELECT 1
postgres=# \d vw_info3
Materialized view "public.vw_info3"
 Column |  Type   | Modifiers 
--------+---------+-----------
 id     | integer | 
 name   | text    | 

postgres=# select * from vw_info3; 
 id  |  name   
-----+---------
 125 | test123
(1 row)

# 往triggerdb数据库里插入一条新数据,再看。
postgres=# insert into triggerdb values(1, 'Bob'); 
INSERT 0 1
postgres=# select * from triggerdb ; 
 id  |  name   
-----+---------
 125 | test123
   1 | Bob
(2 rows)

postgres=# select * from vw_info3; 
 id  |  name   
-----+---------
 125 | test123
(1 row)
# 可以看到物化视图里的数据没有更新,仍然是创建时的数据,这就是它的特性。

但是物化视图里的数据也是可以更新的,需要用到另外的命令格式,分别是:

refresh materialized view view_name with [no] data;
refresh materialized view  concurrently viewname with [no] data;

命令解释:

可更新视图

严格意义上来讲,视图并不是可更新的,因为它的数据只是从其他表中读取,然后在数据库中生成的一张逻辑表。更新视图最后更新的还是视图背后的表。因此在PostgreSQL中实现的视图更新,也还是通过一些内置工具将对视图的更新转为对表的更新。在版本9.4及之前版本,需要通过两种方法来更新,分别是:

  1. 通过规则(rule)来更新
  2. 同过instead of类型的触发器来更新

而在9.5及之后的版本中,已经不需要定义规则或者触发器,视图本身就已经可以更新了,只是会有一些限制,具体的限制是:

同时,如果可更新的视图包含的内容来自两张表或视图,且其中一张表可写,另外一张表只读。那么你更新视图的时候,只能更新那张可写的表或视图。否则会报错。

当一个自动更新的视图包含一个where条件,那么where条件会限制在视图上执行的update或insert语句能够作用的表中的行。最后我们来说说[ WITH [ CASCADED|LOCAL] CHECK OPTION ]这个子句对视图的限制。这个子句的作用是:

示例如下:
先看表info的信息:

postgres=# select * from info; 
 id |        email        |  phone   |  address   | sexual 
----+---------------------+----------+------------+--------
  1 | alias@hotmail.com   | 1234-234 | NewYork    | female
  2 | Bob@gmail.com       | 87222375 | WashingTon | male
  3 | Tom@outlook.com     | 87231634 | NewYork    | male
  4 | Lissa@twitter.com   | 76892342 | NewYork    | male

在这张表的基础上创建4个视图:

# 视图vw_info3用来过滤表中地址address='NewYork'的信息
postgres=# create view vw_info3 as select * from info where address='NewYork'; 
CREATE VIEW

# 视图vw_ny_m是一个普通视图,也是筛选NewYork里sexual='male'的信息。
postgres=# create view vw_ny_m as select * from vw_info3 where sexual = 'male'; 
CREATE VIEW

# 视图vw_ny_m2 带有with local check option子句,用来筛选 NewYork里sexual='male'的信息。
postgres=# create view vw_ny_m2 as select * from vw_info3 where sexual='male' with local check option;
CREATE VIEW

# 视图vw_ny_m3带有with cascaded check option子句,也是筛选NewYork里sexual='male'的信息。
postgres=# create view vw_ny_m3 as select * from vw_info3 where sexual='male' with cascaded check option; 
CREATE VIEW

然后我们来测试往这三个vw_ny_m开头的视图里插入数据:

#往普通的vw_ny_m视图里插入数据,address不匹配,sexual不匹配,可以插入,说明两个where子句都没有生效
postgres=# insert into vw_ny_m values(5, 'Tim@google.com', '87293342', 'Washington', 'female'); 
INSERT 0 1

#往with local check option子句的视图vw_ny_m2里插入数据
# 第一次是address不匹配,sexual不匹配,报错,说明筛选条件生效:
postgres=# insert into vw_ny_m2 values(6, 'Jessica@outlook.com', '98762123', 'Washington', 'female');
ERROR:  new row violates check option for view "vw_ny_m2"
DETAIL:  Failing row contains (6, Jessica@outlook.com, 98762123, Washington, female).

# 第二次是address 不匹配,sexual 匹配,成功插入数据,说明筛选条件只在第二层视图vw_ny_m2的where子句上生效
postgres=# insert into vw_ny_m values(6, 'Jessica@outlook.com', '98762123', 'Washington', 'male');
INSERT 0 1

# 往with cascaded check option子句的视图 vw_ny_m3里插入数据
# 第一次address 不匹配,sexual 匹配,失败,说明筛选条件生效
insert into vw_ny_m3 values(7, 'Jone@goole.com', '9138729', 'Wahsington', 'male');
ERROR:  new row violates check option for view "vw_info3"
DETAIL:  Failing row contains (7, Jone@goole.com, 9138729, Wahsington, male).

# 第二次address 匹配,不sexual 匹配,失败,说明两个视图里的where子句都生效了。
insert into vw_ny_m3 values(7, 'Jone@goole.com', '9138729', 'NewYork', 'female');
ERROR:  new row violates check option for view "vw_info3"
DETAIL:  Failing row contains (7, Jone@goole.com, 9138729, NewYork, female).
视图的修改

视图修改的基本命令格式如下:

ALTER VIEW [ IF EXISTS ] name ALTER [ COLUMN ] column_name SET DEFAULT expression
ALTER VIEW [ IF EXISTS ] name ALTER [ COLUMN ] column_name DROP DEFAULT
ALTER VIEW [ IF EXISTS ] name OWNER TO { new_owner | CURRENT_USER | SESSION_USER }
ALTER VIEW [ IF EXISTS ] name RENAME TO new_name
ALTER VIEW [ IF EXISTS ] name SET SCHEMA new_schema
ALTER VIEW [ IF EXISTS ] name SET ( view_option_name [= view_option_value] [, ... ] )
ALTER VIEW [ IF EXISTS ] name RESET ( view_option_name [, ... ] )

命令解释:

这几个命令都很简单,大家可以自己去做相应的实验示例。

视图的删除

视图的删除命令基本格式如下:
DROP VIEW [ IF EXISTS ] name [, ...] [ CASCADE | RESTRICT ]
删除视图也非常简单,后面带的两个选项的含义是:

这个操作也非常简单,留给读者自己测试了。

至此,视图的所有基本内容讲解完毕。

上一篇下一篇

猜你喜欢

热点阅读