【问题标题】:Replace insert with rule in PostgreSQL在 PostgreSQL 中用规则替换插入
【发布时间】:2021-12-23 03:20:23
【问题描述】:

我想用 PostgreSQL 规则将INSERT 替换成一个表。

这是我的两张桌子:

Resource:
  uid (PK): UUID
  type (NOT_NULL): ENUM

SpecificResource:
  uid (PK, FK on resource.uid): UUID
  content (NOT_NULL): JSONB

我希望数据库的任何用户都能够直接在SpecificResource 上进行插入/更新/删除,而无需在资源上插入/更新/删除。

这是触发无限递归循环的不成功尝试(实际上是因为我尝试使用RULE (...) DO INSTEAD 重新插入specific_resource 表:

CREATE OR REPLACE RULE insert_specific_resource
AS ON INSERT TO specific_resource
DO INSTEAD (
    INSERT INTO resource (uid, type)
    VALUES (NEW.uid, 'SPECIFIC_RESOURCE');
    
    INSERT INTO specific_resource (uid)
    VALUES (new.uid)
);

【问题讨论】:

  • 你坚持使用规则吗?也许是instead of 触发器?
  • 触发器也很好,但它远远超出了我的 SQL 知识范围。
  • 我会推荐一个给你。更容易理解。
  • @Stefanov.sm 以下触发器适用于resource 表。但是,它不会在INSERT INTO specific_resource ...CREATE OR REPLACE FUNCTION add_specific_resource() RETURNS TRIGGER AS $BODY$ BEGIN INSERT INTO resource(uid, type) VALUES (uid, 'SPECIFIC_RESOURCE'); RETURN NEW; END $BODY$ LANGUAGE PLPGSQL; CREATE OR REPLACE TRIGGER add_dashboard BEFORE INSERT ON dashboard FOR EACH ROW EXECUTE PROCEDURE add_specific_resource();CREATE OR REPLACE FUNCTION add_specific_resource() RETURNS TRIGGER AS $BODY$ BEGIN INSERT INTO resource(uid, type) VALUES (uid, 'SPECIFIC_RESOURCE'); RETURN NEW; END $BODY$ LANGUAGE PLPGSQL; CREATE OR REPLACE TRIGGER add_dashboard BEFORE INSERT ON dashboard FOR EACH ROW EXECUTE PROCEDURE add_specific_resource();specific_resource 表中插入任何内容

标签: sql database postgresql


【解决方案1】:
create or replace function specific_resource_tf()
returns trigger language plpgsql as
$$
begin
 insert into resource(uid, type) VALUES (new.uid, 'SPECIFIC_RESOURCE');
 return new;
end;
$$;

create trigger specific_resource_t 
before insert on specific_resource
for each row
execute procedure specific_resource_tf();

解释

创建触发器specific_resource_t 后,它将在每次插入表specific_resource 之前执行。触发器调用函数specific_resource_tf,它执行您的规则的意图 - 在继续插入表specific_resource 之前将记录插入resource

插图(带有临时表和函数)

-- drop table if exists specific_resource; drop table if exists resource;
create temp table resource (uid integer primary key, type text);
create temp table specific_resource (uid integer references resource(uid), content JSONB);  

create or replace function pg_temp.specific_resource_tf()
returns trigger language plpgsql as $$
begin
 insert into resource(uid, type) VALUES (new.uid, 'SPECIFIC_RESOURCE');
 return new;
end;
$$;

create trigger specific_resource_t 
before insert on specific_resource
for each row execute procedure pg_temp.specific_resource_tf();

insert into specific_resource values (22, '"test"');
-- does insert in both tables

【讨论】:

  • 感谢您的回答。当我执行 INSERT INTO specific_resource (uid, content) VALUES ('an_uuid', '"test'") 时,它不会在 specific_resource 中插入任何行
  • 我不相信。有任何错误信息吗?
  • 似乎 pgadmin 中的语法错误:ERROR: syntax error at or near ";" 最后一个字符。如果我添加括号它可以工作,但我猜它没有调用函数,而是尝试定义它......但仍然在resource而不是specific_resource中添加一行。奇怪
  • 我的遗漏。在create trigger 语句的末尾错过了()。已在答案中修复。
  • 当然 :) 尽管如此,它仍然可以正确插入 resource 而不是 specific_resource..
【解决方案2】:
CREATE OR REPLACE FUNCTION add_specific_plus_resource()
RETURNS TRIGGER LANGUAGE PLPGSQL AS 
$$
BEGIN
    INSERT INTO resource(uid, type)
    VALUES (uid, 'SPECIFIC');
    RETURN NEW;
END;
$$;

CREATE OR REPLACE TRIGGER add_specific_resource
BEFORE INSERT ON specific_resource
FOR EACH ROW EXECUTE PROCEDURE add_specific_plus_resource();

以下INSERT 可以很好地向resource 添加一行,但不能向specific_resource 添加一行。

INSERT INTO specific_resource(uid, content)
VALUES ('123e4567-e89b-12d3-a456-426614174000', '"test"');

【讨论】:

  • 请。请注意 OR REPLACE 对于 create trigger 是非法的
  • @Stefanov.sm 你成功了,它就像一个魅力,非常感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-17
  • 1970-01-01
  • 2023-04-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多