【问题标题】:Delete row of referencing composite key BEFORE DELETE on each row在每一行上删除引用复合键的行
【发布时间】:2014-04-14 20:25:54
【问题描述】:

我的数据库中有以下表格:

CREATE TABLE tableA (   id integer NOT NULL,   ...,   PRIMARY KEY (id)
);

CREATE TABLE tableB (   id integer NOT NULL,   ...,   PRIMARY KEY (id)
);

CREATE TABLE as_for_bs (
    idA integer REFERENCES tableA(id),
    idB integer REFERENCES tableB(id),
    PRIMARY KEY (idA, idB) );

还有以下触发器:

表A

CREATE OR REPLACE FUNCTION remove_A() RETURNS trigger AS $BODY$ BEGIN
    DELETE from as_for_bs WHERE idA = OLD.id;
    RETURN OLD; END $BODY$ LANGUAGE plpgsql;

CREATE TRIGGER remove_as_from_bs_from_A BEFORE DELETE ON tableA FOR
EACH ROW EXECUTE PROCEDURE remove_A();

表B

CREATE OR REPLACE FUNCTION remove_B() RETURNS trigger AS $BODY$ BEGIN
    DELETE from as_for_bs WHERE idB = OLD.id;
    RETURN OLD; END $BODY$ LANGUAGE plpgsql;

CREATE TRIGGER remove_as_for_bs_from_B BEFORE DELETE ON tableB FOR
EACH ROW EXECUTE PROCEDURE remove_B();

我的问题是当我从 B 中删除一行时,as_for_bs 中的引用行会相应地删除。但是当我从 A 中删除一行时,我得到了错误:

错误:表“tableA”上的更新或删除违反了外键约束 “as_for_bs”表上的“as_for_bs_fkey”
详细信息:键 (id)=(999999) 仍从表“tableA”中引用。

我不明白为什么我的触发删除在复合键的一个字段上而不是另一个字段上时有效。这样的事情应该正常工作吗?有什么理由不这样做吗?

**附注:**

我知道像 as_for_bs 这样的表可能有点多余,但我真的只是想在这里测试一些东西。在 tableA 和 tableB 中插入值时还有很多事情要做。我已经在我的数据库中集成了 PostGIS,每次添加元素“A”或“B”时,我都会检查它是否适合另一个表。我想预先计算 A 在 B 中的所有实例并将它们添加到表中,以便我可以比使用 st_contains( ) 在表 A 的每一行上。我尝试在 tableA 中添加一个数组,其中包含 tableB 中的所有 id,其中 'A' 位于其中,但是查询 tableB 中的 id 是否 = ANY(arrayInTableA) 并没有更快。

编辑:那是一些丑陋的格式...抱歉,我不太确定格式如何在 SO 上工作...我会尽快调查。

【问题讨论】:

    标签: postgresql triggers foreign-keys composite-primary-key delete-row


    【解决方案1】:

    您需要的是ON DELETE CASCADEON UPDATE CASCADE 在您的as_for_bs 表中。

    因此,as_for_bscreate table 脚本应如下所示

    CREATE TABLE as_for_bs 
    (idA integer REFERENCES tableA(id) 
    ON DELETE CASCADE 
    ON UPDATE CASCADE, 
    idB integer REFERENCES tableB(id) 
    ON DELETE CASCADE 
    ON UPDATE CASCADE, 
    PRIMARY KEY (idA, idB) );
    

    现在,每当您删除/更新父/基表中的一行时,相同的更改将级联/传播到子/派生/引用表。

    【讨论】:

      【解决方案2】:

      如果只是删除引用表中的条目,使用带有 ON DELETE CASCADE 的外键似乎要容易得多。

      无论如何,如果您愿意并且希望将来执行更复杂的操作,您可以使用触发器。您的代码对我来说看起来不错,即使我认为没有必要同时使用触发器和函数。你可以同时做到这一切:

      DELIMITER //
      CREATE TRIGGER remove_as_from_bs_from_A BEFORE DELETE ON tableA 
      FOR EACH ROW 
      BEGIN 
          DELETE FROM as_for_bs 
          WHERE idA = OLD.id;
      END //
      CREATE TRIGGER remove_as_from_bs_from_B BEFORE DELETE ON tableB
      FOR EACH ROW 
      BEGIN 
          DELETE FROM as_for_bs 
          WHERE idB = OLD.id;
      END //
      DELIMITER ;
      

      编辑:我的错,我没有看到它是 PgSQL 而不是 MySQL 数据库,那么语法可能不正确。

      【讨论】:

        猜你喜欢
        • 2017-12-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-07-25
        • 1970-01-01
        • 2022-09-27
        • 1970-01-01
        相关资源
        最近更新 更多