【问题标题】:How to create a conditional trigger如何创建条件触发器
【发布时间】:2018-07-26 05:59:45
【问题描述】:

我有一个 id 作为自动递增主键和另一个 id 的表。

CREATE TABLE tester (
"id" integer PRIMARY KEY AUTOINCREMENT,
"refId" integer DEFAULT 0
);

refId 应该能够为 0(默认值)或引用 id 如果 refId > 0(即充当外键)。

现在我需要两个约束:

  1. 只有当行的 id 未被任何其他行的 refId 使用(引用?)时,该行才可删除
  2. 只有 refId 为 0 的行才可删除。

据我了解,我需要创建一个触发器,在 DELETE 事件发生之前检查这些约束。并根据 refId 的值中止或允许删除操作。

但是,我很难理解它的语法以及如何进行条件检查。但到目前为止我所知道的(记住!)是关于 1.):

CREATE TRIGGER no_delete_if_inuse
BEFORE DELETE ON tester
FOR EACH ROW BEGIN
    SELECT RAISE(ABORT, 'cannot delete because of foreign key violation')
    WHERE  (SELECT "refId" FROM tester WHERE "refId" = OLD."id") IS NOT NULL;        
END;

关于 2.)

CREATE TRIGGER no_delete_if_ref
BEFORE DELETE ON tester
FOR EACH ROW BEGIN
    IF OLD."refId" > 0 THEN RAISE(ABORT, "cannot delete tester because it refers to an existing tester");
END;

这有意义并且有效吗? 我完全不确定,对我来说确实如此,但很好,我都是菜鸟。

最后一个问题,我可以将它组合成一个触发器吗?例如,这是否是一个有效的查询:

CREATE TRIGGER no_delete_if_inuse
    BEFORE DELETE ON tester
    FOR EACH ROW BEGIN
        SELECT RAISE(ABORT, 'cannot delete because of foreign key violation')
        WHERE  (SELECT "refId" FROM tester WHERE ("refId" = OLD."id" OR "refId" > 0) ) IS NOT NULL;        
    END;

【问题讨论】:

    标签: sql postgresql sqlite triggers


    【解决方案1】:

    您可以定义引用同一个表的外键。对没有引用的行使用null 而不是0

    create table tester(
        id int primary key, 
        refid int references tester,
        check (id <> refid)
    );
    
    insert into tester values
    (1, null),
    (2, null),
    (3, 1),
    (4, 3);
    

    您需要一个触发器来确保不能删除引用另一行的行。

    create or replace function before_delete_on_tester()
    returns trigger language plpgsql as $$
    begin
        if old.refid is not null then
            raise exception 
                'Cannot delete: (id)=(%) references (id)=(%)', old.id, old.refid;
        end if;
        return old;
    end $$;
    
    create trigger before_delete_on_tester
    before delete on tester
    for row execute procedure before_delete_on_tester();
    

    测试:

    delete from tester where id = 1;
    
    ERROR:  update or delete on table "tester" violates foreign key constraint "tester_refid_fkey" on table "tester"
    DETAIL:  Key (id)=(1) is still referenced from table "tester".  
    
    delete from tester where id = 4;
    
    ERROR:  Cannot delete from tester. (id)=(4) references (id)=(3)
    CONTEXT:  PL/pgSQL function before_delete_on_tester() line 4 at RAISE   
    

    在 Postgres 中你必须定义一个触发函数。阅读更多:

    【讨论】:

    • 感谢您的回答。这很有帮助,但如果它有关于如何将我的 SELECT 语句合并到触发器函数中的信息,那将是完美的(文档在这方面根本没有帮助,因为那里也没有任何提示,只有简单的条件 IF。 .ELSE IF 等)以及组合的外观。我花了一段时间才掌握。但由于这是唯一的答案,而且对获得基本理解非常有帮助,我给它一个“正确”:) 干杯
    猜你喜欢
    • 1970-01-01
    • 2015-03-01
    • 2023-03-26
    • 1970-01-01
    • 1970-01-01
    • 2022-07-29
    • 2019-03-28
    • 2021-12-16
    • 2010-10-08
    相关资源
    最近更新 更多