删除每行上引用复合键BEFORE DELETE的行

时间:2014-04-14 20:25:55

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

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

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) );

以下触发器:

表tableA

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();

for tableB

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”
  DETAIL:Key(id)=(999999)仍然从表“tableA”引用。

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

**旁注:**

我知道像as_for_bs这样的表可能有点多余,但我真的只是想在这里测试一些东西。在tableA和tableB中插入值时会发生很多事情。我已将PostGIS集成到我的数据库中,每次添加元素“A”或“B”时,我都会检查它是否适合其他表格。我想预先计算A在B中的所有实例,并将它们添加到表中,这样我就可以希望查询tableB的给定id内的所有'A'实例比使用st_contains更快一些( )在tableA的每一行上。我尝试在tableA中添加一个数组,其中包含来自tableB的所有id,其中'A'在里面,但是查询tableB中的id是否为= ANY(arrayInTableA)的查询速度并不快。

编辑:这是一些丑陋的格式......对不起,我不太确定格式化的工作原理......我很快就会调查它。

2 个答案:

答案 0 :(得分:0)

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

因此create table的{​​{1}}脚本应如下所示

as_for_bs

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

答案 1 :(得分:0)

如果它只删除引用表中的条目,则使用带有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数据库,语法可能不正确。