如何使用PL / pgSQL触发器限制删除?

时间:2018-02-01 10:42:18

标签: postgresql triggers plpgsql postgresql-9.6

如果客户端用户试图从表中删除超过5条记录,我想使用触发器限制它。我有一个基本的想法,但我不知道如何实现这个想法。我感谢任何帮助。

基本理念:在触发器中IF TG_OP =删除且要删除的记录数大于5然后限制。

CREATE TRIGGER adjust_count_trigger BEFORE DELETE ON schemaname.tablename
FOR EACH ROW EXECUTE PROCEDURE public.adjust_count();

CREATE OR REPLACE FUNCTION adjust_count()
RETURNS TRIGGER AS
$$
    DECLARE
        num_rows int;
        num_rows1 int;

    BEGIN

        IF TG_OP = 'DELETE' THEN

            EXECUTE 'select count(*) from '||TG_TABLE_SCHEMA ||'.'||TG_RELNAME ||' where oid = old.oid ' into num_rows  ;


            IF num_rows > 5   Then

            RAISE NOTICE 'Cannot Delete More than 5 Records , % ', num_rows ;

            END IF ;


        END IF ;

        RETURN OLD;
    END;
$$
LANGUAGE 'plpgsql';

2 个答案:

答案 0 :(得分:2)

在早期版本的Postgres中,您可以模拟Postgres 10中引入的转换表。您需要两个触发器。

create trigger before_delete 
before delete on my_table
for each row execute procedure before_delete();

create trigger after_delete 
after delete on my_table
for each statement execute procedure after_delete();

在第一个触发器中创建一个临时表并在其中插入一行:

create or replace function before_delete()
returns trigger language plpgsql as $$
begin
    create temp table if not exists deleted_rows_of_my_table (dummy int);
    insert into deleted_rows_of_my_table values (1);
    return old;
end $$;

在临时表的其他触发计数行中删除它:

create or replace function after_delete()
returns trigger language plpgsql as $$
declare
    num_rows bigint;
begin
    select count(*) from deleted_rows_of_my_table into num_rows;
    drop table deleted_rows_of_my_table;
    if num_rows > 5 then
        raise exception 'Cannot Delete More than 5 Records , % ', num_rows;
    end if;
    return null;
end $$;

上面的解决方案可能看起来有点hacky但是如果在删除之前只有临时表不存在则是安全的(不要对多个表使用临时表的相同名称)。

Test it in rextester.

答案 1 :(得分:1)

您可以使用PostgreSQL v10中的新过渡关系功能轻松完成此操作:

CREATE OR REPLACE FUNCTION forbid_more_than() RETURNS trigger
   LANGUAGE plpgsql AS
$$DECLARE
   n bigint := TG_ARGV[0];
BEGIN
   IF (SELECT count(*) FROM deleted_rows) <= n IS NOT TRUE
   THEN
      RAISE EXCEPTION 'More than % rows deleted', n;
   END IF;
   RETURN OLD;
END;$$;

CREATE TRIGGER forbid_more_than_5
   AFTER DELETE ON mytable
   REFERENCING OLD TABLE AS deleted_rows
   FOR EACH STATEMENT
   EXECUTE PROCEDURE forbid_more_than(5);