美文网首页
12. 视图

12. 视图

作者: shark_tear | 来源:发表于2018-02-07 13:34 被阅读0次

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

    视图的作用

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

    视图的分类

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

    视图的定义

    命令格式如下所示:

    CREATE [OR REPLACE] [TEMP | TEMPORARY ] [MATERIALIZED] VIEW view_name (field1, field2....) 
    AS query
    [ WITH [ CASCADED | LOCAL ] CHECK OPTION ]
    
    • 可以创建或替换当前已有的视图;
    • 可以创建临时视图,当会话结束时,视图消失;
    • 可以创建物化视图,表中的数据全部存储在视图里,查询时不用查原来的表;
    • 可以在视图名称view_name后面的括号里定义视图里的字段名称。
    • query语句可以是查询语句,也可以是执行函数。

    示例如下
    示例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;
    

    命令解释:

    • 命令里的concurrently表示增量更新数据,即将视图当前的数据和查询语句获取到的数据进行对比,然后将视图中没有的数据更新到视图里去。
    • 默认带with data和不带这个参数效果一致。但是如果带了no关键字,那么会把这个视图变成不可读状态。

    可更新视图

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

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

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

    • 视图更新的对象必须是一张表或另外一个可更新的视图
    • 视图定义不能在顶层包含WITH,DISTINCT,GROUP BY,HAVING,LIMIT或OFFSET等子句
    • 视图定义在顶层不能包含集合操作,例如UNION,INTERSECT或EXCEPT等。
    • 视图的select列表不能包含聚合、窗口函数或者返回集合的函数。

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

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

    • 创建视图时,A视图基础上创建B视图,A视图上有一个where子句,B视图上也有一个where子句。那么在对带有WITH LOCAL CHECK OPTION的B视图进行更新时,只会检查B视图where子句里的条件,A视图里的where子句会跳过。
    • 创建视图时,A视图基础上创建B视图。A视图上有一个where子句,B视图上也有where子句,那么在对带有WITH CASCADED CHECK OPTION的B视图进行更新时,会同时检查这两个where子句。

    示例如下:
    先看表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 [, ... ] )
    

    命令解释:

    • 第一个用于设置视图里的某个字段的默认值
    • 第二个用于删除视图里某个字段的默认值
    • 第三个用于设置视图的所有者为新的所有者/ 当前用户/会话用户
    • 第四个用户重命名视图
    • 第五个用于修改视图所在的模式
    • 第六个用于设置视图的一些属性,例如上面我们讲到的check option。它的属性名称是check_option,对应的值是local或cascaded
    • 第七个用于修改对应的属性值。
    • IF EXISTS 选项用于在视图不存在时不报错,只输出提示信息,同样适用于删除视图

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

    视图的删除

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

    • cascade 表示删除这个视图时,同时删除依赖在这个视图上的其他对象。比如说函数、其他视图等。
    • restrict 表示当有其他对象依赖在当前视图上时,不删除该视图。这是默认选项。

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

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

    相关文章

      网友评论

          本文标题:12. 视图

          本文链接:https://www.haomeiwen.com/subject/kukxzxtx.html