PostgreSql 规则

一、概述

  其它数据库系统定义活动的数据库规则,通常是存储过程和触发器。在 PostgreSQL 中,这些东西可以通过函数和触发器来实现。规则系统(更准确地说是查询重写规则系统)与存储过程和触发器完全不同。它把查询修改为需要考虑规则,并且然后把修改过的查询传递给查询规划器进行规划和执行。它非常强大,并且可以被用于许多东西如查询语言过程、视图和版本。
  PostgreSQL 规则系统允许我们定义针对数据库表中插入、更新或者删除动作上的替代动作。比如当在一个给定表上执行给定命令时,一条规则会导致执行额外的命令。或者,INSTEAD 规则可以用另一个命令替换给定的命令,或者导致一个命令根本不被执行。规则也被用来实现 SQL 视图。规则实际上是一种命令转换机制,这种转换会在命令的执行开始之前进行。如果你上想要为每一个物理行独立地触发一个操作,你可能更需要一个触发器而不是规则。

二、创建规则

2.1 语法

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

其中 event 可以是以下之一:

    SELECT | INSERT | UPDATE | DELETE

参数说明

name:要创建的规则的名称。它必须与同一个表上任何其他规则的名称相区分。 同一个表上同一种事件类型的多条规则会按照其名称的字符顺序被应用。
event:事件是 SELECT、 INSERT、UPDATE 或者 DELETE 之一。 注意包含 ON CONFLICT 子句的 INSERT 不能被用在具有 INSERT 或者 UPDATE 规则的表上。那种情况下请考虑使用可更新的视图。
table_name:规则适用的表或者视图的名称(可以是模式限定的)。
condition:任意的SQL条件表达式(返回 boolean)。该条件表达式不能引用除 NEW 以及 OLD 之外的任何表,并且不能包含聚集函数。
INSTEAD:INSTEAD 指示该命令应该取代原始命令被执行。
ALSO:ALSO指示应该在原始命令之外执行这些命令。如果 ALSO 和 INSTEAD 都没有被指定, 默认是 ALSO。
command:组成规则动作的命令。可用的命令有 SELECT、 INSERT、UPDATE、 DELETE 或者 NOTIFY。

  在 condition 和 command 中,名为 NEW 和 OLD 的表可以被用来引用被引用表中的值。在 ON INSERT 和 ON UPDATE 规则中,NEW 被用来引用被插入或者更新的新行。在 ON UPDATE 和 ON DELETE 规则中,OLD 被用来引用被更新或者删除的现有行。

SELECT 规则有如下限制:

  • 后续动作只能是INSTEAD。
  • 规则的名称只能是“_RETURN”。
  • 只能创建在空表上。

2.2 示例

--创建 select 规则将表转换为视图
postgres=# create table t(id int,name varchar);
CREATE TABLE
postgres=# create table t_v(like t);
CREATE TABLE
postgres=# \dt
            List of relations
 Schema |      Name      | Type  | Owner
--------+----------------+-------+--------
 public | t              | table | postgres
 public | t_v            | table | postgres
(2 rows)

postgres=# create rule "_RETURN" as on select to t_v do instead select * from t;
CREATE RULE
postgres=# \dt
            List of relations
 Schema |      Name      | Type  | Owner
--------+----------------+-------+--------
 public | t              | table | postgres
(1 rows)

postgres=# \dv
              List of relations
 Schema |        Name        | Type | Owner
--------+--------------------+------+--------
 public | t_v                | view | postgres
(1 rows)

--创建 insert 规则禁止插入数据
postgres=# select * from t;
 id | name
----+-------
  1 | xiaoo
  2 | xiaoh
  3 | guo
  4 | wan
  5 | piao
  6 | pen
(6 rows)
postgres=# create rule t_r as on insert to t do instead nothing;
CREATE RULE
postgres=# insert into t values(7,'cha');
INSERT 0 0
postgres=# select * from t;
 id | name
----+-------
  1 | xiaoo
  2 | xiaoh
  3 | guo
  4 | wan
  5 | piao
  6 | pen
(6 rows)

三、修改规则

3.1 语法

当前唯一可用的动作是更改规则的名称

ALTER RULE name ON table_name RENAME TO new_name

参数说明

name:要修改的一条现有规则的名称。
table_name:该规则适用的表或视图的名称(可以是模式限定的)。
new_name:该规则的新名称。

3.2 示例

postgres=# alter rule t_r on t rename to t_rule;
ALTER RULE

四、删除规则

4.1 语法

DROP RULE [ IF EXISTS ] name ON table_name [ CASCADE | RESTRICT ]

4.2 示例

postgres=# drop rule t_rule on t;
DROP RULE

五、利用规则实现记录操作日志

5.1 创建测试表、日志表

postgres=# create table test(id int primary key,note text);
CREATE TABLE
postgres=# create table test_log(seq bigserial primary key,oprtype char(1),oprtime timestamp,id int,note text);
CREATE TABLE

5.2 创建规则

--插入规则,记为"i"
postgres=# create rule rule_test_insert as on insert to test do also insert into test_log(oprtype,oprtime,id,note) values('i',now(),new.id,new.note);
CREATE RULE

--删除规则,记为"d"
postgres=# create rule rule_test_delete as on delete to test do also insert into test_log(oprtype,oprtime,id,note) values('d',now(),old.id,old.note);
CREATE RULE

--更新规则,先删除旧数据再入新数据
postgres=# create rule rule_test_update as on update to test do also (insert into test_log(oprtype,oprtime,id, note) values('d',now(),old.id,old.note);insert into test_log(oprtype,oprtime,id, note) values('i',now(),new.id,new.note));
CREATE RULE

5.3 操作示例

postgres=# insert into test values(1,'1111');
INSERT 0 1
postgres=# insert into test values(2,'2222');
INSERT 0 1
postgres=# insert into test values(3,'3333');
INSERT 0 1
postgres=# select * from test;
 id | note
----+------
  1 | 1111
  2 | 2222
  3 | 3333
(3 rows)

postgres=# select * from test_log;
 seq | oprtype |          oprtime           | id | note
-----+---------+----------------------------+----+------
   1 | i       | 2023-12-05 17:33:27.60072  |  1 | 1111
   2 | i       | 2023-12-05 17:33:38.943318 |  2 | 2222
   3 | i       | 2023-12-05 17:33:45.038311 |  3 | 3333
(3 rows)

postgres=# update test set note='3333' where id = 3;
UPDATE 1
postgres=# select * from test;
 id | note
----+------
  1 | 1111
  2 | 2222
  3 | 3333
(3 rows)

postgres=# select * from test_log;
 seq | oprtype |          oprtime           | id | note
-----+---------+----------------------------+----+------
   1 | i       | 2023-12-05 17:33:27.60072  |  1 | 1111
   2 | i       | 2023-12-05 17:33:38.943318 |  2 | 2222
   3 | i       | 2023-12-05 17:33:45.038311 |  3 | 3333
   4 | d       | 2023-12-05 17:34:05.81583  |  3 | 3333
   5 | i       | 2023-12-05 17:34:05.81583  |  3 | 3333
(5 rows)

postgres=# delete from test where id =3;
DELETE 1
postgres=# select * from test;
 id | note
----+------
  1 | 1111
  2 | 2222
(2 rows)

postgres=# select * from test_log;
 seq | oprtype |          oprtime           | id | note
-----+---------+----------------------------+----+------
   1 | i       | 2023-12-05 17:33:27.60072  |  1 | 1111
   2 | i       | 2023-12-05 17:33:38.943318 |  2 | 2222
   3 | i       | 2023-12-05 17:33:45.038311 |  3 | 3333
   4 | d       | 2023-12-05 17:34:05.81583  |  3 | 3333
   5 | i       | 2023-12-05 17:34:05.81583  |  3 | 3333
   6 | d       | 2023-12-05 17:34:45.209414 |  3 | 3333
(6 rows)

你可能感兴趣的:(PostgreSql,学习笔记,postgresql,数据库)