简体   繁体   English

Postgres:忽略级联删除的 DELETE 触发器

[英]Postgres: Ignore DELETE triggers for cascade deletes

I am trying to implement a relation of persons to email addresses where a person must have at least one email address at all times.我正在尝试实现人员与 email 地址的关系,其中一个人必须始终拥有至少一个 email 地址。 The tables look like this:表格如下所示:

CREATE TABLE persons (
    id serial PRIMARY KEY,
    name text NOT NULL
);

CREATE TABLE email_addresses (
    id serial PRIMARY KEY,
    person_id integer REFERENCES persons (id) ON DELETE CASCADE ON UPDATE CASCADE,
    email_address text NOT NULL
);

In order to implement the constraint that a person must have at least one email address, I thought I'd use triggers.为了实现一个人必须至少有一个 email 地址的约束,我想我会使用触发器。 One of the triggers necessary to satisfy the constraint is a BEFORE DELETE trigger on the email_addresses table that raises an error if the DELETE would remove the last email address for a person:满足约束所必需的触发器之一是email_addresses表上的BEFORE DELETE触发器,如果DELETE将删除一个人的最后一个 email 地址,则会引发错误:

CREATE FUNCTION email_addresses_delete_trigger() RETURNS trigger AS $$
    DECLARE
        num_email_addresses integer;
    BEGIN
        num_email_addresses := (SELECT count(*) FROM email_addresses WHERE person_id = OLD.person_id);
        IF num_email_addresses < 2 THEN
            RAISE EXCEPTION 'A person must have at least one email address';
        END IF;

        RETURN OLD;
    END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER email_addresses_delete_trigger BEFORE DELETE ON email_addresses
    FOR EACH ROW EXECUTE FUNCTION email_addresses_delete_trigger();

This trigger does what it is meant to do, however it prevents deletes of a person from the persons table.这个触发器做了它应该做的事情,但是它阻止了从persons表中删除一个人。 For example:例如:

mydb=# DELETE FROM persons WHERE id = 1;
ERROR:  A person must have at least one email address
CONTEXT:  PL/pgSQL function email_addresses_delete_trigger() line 7 at RAISE
SQL statement "DELETE FROM ONLY "public"."email_addresses" WHERE $1 OPERATOR(pg_catalog.=) "person_id""

If I am deleting a person, then I want all their email addresses deleted too, and so I don't care if the constraint represented by the trigger is maintained during the process of the cascade delete.如果我要删除一个人,那么我也希望删除他们所有的 email 地址,因此我不在乎在级联删除过程中是否保持触发器表示的约束。 Is there a way to "ignore" this trigger when a person is deleted?当一个人被删除时,有没有办法“忽略”这个触发器? Or is there some other way that I would need to delete a person?还是有其他方法我需要删除一个人?

My recommendation is to change the data model so that you have a not nullable foreign key constraint from persons to email_addresses that links to one of the addresses of the person.我的建议是更改数据 model 以便您有一个不可为空的外键约束,从personsemail_addresses链接到人员的地址之一。 Then your requirement is automatically fulfilled, and you don't need a trigger.然后您的要求会自动满足,您不需要触发器。

That will make some things like deleting an e-mail address more complicated, but you don't have to rely on a trigger for integrity, which is always subject to race conditions .这将使删除电子邮件地址之类的事情变得更加复杂,但您不必依赖触发器来确保完整性,因为完整性总是受制于竞争条件

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM