Postgresql学习笔记之——规则系统简述

本文深入探讨了PostgreSQL中的规则系统,包括SELECT规则用于视图创建,更新规则用于记录操作日志,以及规则与权限、触发器之间的区别。通过实例展示了如何使用规则系统增强数据库功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

规则系统,准确的说就是查询重写规则的系统。从使用上说,规则系统上的一些功能也可以通过函数或者触发器来实现,但是规则与触发器完全不同,他在执行前把用户发过来的SQL语句通过内部的规则定义改变成另一个SQL后再执行的一种方式。

1.select规则

Postgresql的视图是通过select规则来实现的。
创建视图的命令如下:

postgres=# select * from student ;
 student_no | student_name | age | sex 
------------+--------------+-----+-----
          1 | 李四         |  16 | 
          2 | 张三         |  16 | 
          3 | 王二3        |  19 | 
          4 | scott        |  22 | f
          5 | Lily         |  18 | t
          6 | smith        |  20 | f
          7 | Tom          |  19 | f
          8 | Jack         |  20 | f
          9 | kate         |  17 | t
         10 | Finity       |  22 | t
(10 rows)

postgres=# create view v_stu as select * from student ;
CREATE VIEW

创建视图的语句与下面的两个命令时等同的:

create table v_stu (same column list as student);
create rule "_RETURN" AS ON SELECT TO v_stu DO INSTEAD select * from student;

由此可见,视图实际上是一张表,不过是在这张表上加了一个SELECT规则。

SELECT规则使用方法:
先创建一个测试表,如下:

postgres=# create table mytab1(id int,note varchar(40));
CREATE TABLE
postgres=# create table mytab2(id int,note varchar(40));
CREATE TABLE
postgres=# create rule myrule as on select to mytab2 do instead select * from mytab1;
ERROR:  view rule for "mytab2" must be named "_RETURN"

在mytab2上创建SELECT规则,只能是**“INSTEAD SELECT”,即只能用另一个SELECT语句取代。
而且使用自定义的规则名称
myrule会提示报错,因为SELECT规则只能使用“_RETURN”**这个名称来命名规则:

postgres=# create rule "_RETURN" as on select to mytab2 do instead select * from mytab1;
CREATE RULE

SELECT规则创建成功后你会发现创建的表mytab2变成了视图!!

2.更新规则

更新规则是指在插入、更新或删除上定义的规则。更新规则与上面的SELECT规则完全不同,它允许用户有更多的操作。
创建更新规则的语法如下:

CREATE [ OR REPLACE ] RULE name AS ON event
    TO table [ WHERE condition ]
    DO [ ALSO | INSTEAD ] { NOTHING | command | ( command ; command ... ) }

语法中的**“event”**可以取下列值:

(1)SELECT:上述介绍过的SELECT规则,当SQL的查询计划中存在查询表的操作时会重写查询计划。
(2)INSERT:当SQL的查询计划中存在向表中插入数据的操作时会重写查询计划。
(3)UPDATE:当SQL的查询计划中存在向表中更新数据的操作时会重写查询计划。
(4)DELETE:当SQL的查询计划中存在将表中数据删除的操作时会重写查询计划。

而更新规则就包括了INSERT、UPDATE、DELETE。

语法中的**“ALSO”、“INSTEAD”**说明如下:

(1)ALSO:除了执行原本操作外,还执行一些附加操作,这些附加操作由后面的 “command” 指定。
(2)INSTEAD:用后面的 “command” 操作代替原操作。

语法中的**“NOTHING”**表示什么都不执行。

示例
创建一张测试表,然后创建对这张表操作记录的日志表:

postgres=# create table mytab(id int primary key,note varchar(40));
CREATE TABLE
postgres=# create table mytab_log(seq bigserial primary key,
postgres(# oprtype char(1),
postgres(# oprtime timestamp,
postgres(# old_id int,
postgres(# new_id int,
postgres(# old_note text,
postgres(# new_note text);
CREATE TABLE

日志表中有一个序列字段seq作为主键,这样可以记录操作表mytab的先后执行顺序,oprtype记录操作的类型(insert为‘i’、update为‘u’、delete为‘d’),old_id、old_note、new_id、new_note分别记录表mytab中id和note字段的操作过程中的旧值和新值。

创建三个规则来实现日志记录操作的功能:

postgres=# CREATE RULE rule_mytab_insert AS ON INSERT TO mytab 
DO ALSO INSERT INTO mytab_log (oprtype, oprtime, new_id, new_note)
VALUES('i', now(), new.id, new.note);
CREATE RULE
postgres=# CREATE RULE rule_mytab_update AS ON UPDATE TO mytab 
DO ALSO INSERT INTO mytab_log (oprtype, oprtime, old_id, old_note, new_id, new_note)
VALUES('u', now(), old.id, old.note, new.id, new.note);
CREATE RULE
postgres=# CREATE RULE rule_mytab_delete AS ON DELETE TO mytab 
DO ALSO INSERT INTO mytab_log (oprtype, oprtime, old_id, old_note)
VALUES('d', now(), old.id, old.note);
CREATE RULE

然后对表mytab插入、更新和删除数据,看看效果:

postgres=# insert into mytab values(1,'zhang');
INSERT 0 1
postgres=# insert into mytab values(2,'ya');
INSERT 0 1
postgres=# insert into mytab values(3,'hui');
INSERT 0 1
postgres=# update mytab set note='1111' where id=1;
UPDATE 1
postgres=# update mytab set note='2222' where id=2;
UPDATE 1
postgres=# delete from mytab where id='3';
DELETE 1
postgres=# select * from mytab_log;
 seq | oprtype |          oprtime           | old_id | new_id | old_note | new_note 
-----+---------+----------------------------+--------+--------+----------+----------
   1 | i       | 2020-04-12 11:10:45.192234 |        |      1 |          | zhang
   2 | i       | 2020-04-12 11:10:52.378097 |        |      2 |          | ya
   3 | i       | 2020-04-12 11:10:58.722165 |        |      3 |          | hui
   4 | u       | 2020-04-12 11:11:35.044123 |      1 |      1 | zhang    | 1111
   5 | u       | 2020-04-12 11:11:47.06058  |      2 |      2 | ya       | 2222
   6 | d       | 2020-04-12 11:11:58.420889 |      3 |        | hui      | 
(6 rows)

以上结果看出规则的效果,实际上上面日志表中插入操作,旧值总是空的,删除操作新值总是空的,会显得日志表结构不紧凑,可以优化一下,将更新操作拆解为删除旧值然后插入新值的操作,这样日志表就可以省略新旧值的区分了,只需要更改UPDATE规则即可:

postgres=# CREATE RULE rule_mytab_update AS ON UPDATE TO mytab 
DO ALSO (
INSERT INTO mytab_log (oprtype, oprtime, id, ote)
VALUES('d', now(), old.id, old.note);
INSERT INTO mytab_log (oprtype, oprtime, id, note)
VALUES('i', now(),  new.id, new.note);
)
CREATE RULE

当然日志表结构就只保留id、note两个字段。

3、规则和权限

规则(RULE)是从属表或试图的。因规则的食欲欧诺个的关系要对定义规则的属主进行权限检查,而不是检查执行规则的用户,这意味着一个用户只需要对查询里的明确执行的表或试图拥有所需的权限就可以进行操作。

说白了,就是用户只有对有相应权限的表或试图进行操作,例如用户b将一张视图view查询权限给了用户a,那么用户a就可以查询用户b的视图view,但是用户b没有授权视图view底层中表table的权限,所以用户a无法查询视图底层表table。

4、规则和触发器的比较

在Postgresql数据库中从外部到数据的命令 “COPY FROM” 会让触发器执行,但是不会调用规则系统。

触发器能做的在Postgresql数据库中规则系统也可以完成,使用哪种方式取决于具体的应用环境,只不过对于批量操作的场景如果使用规则,可能会生成更好的执行计划,提高效率。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Major_ZYH

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值