簡體   English   中英

PostgreSQL刪除失敗,並在繼承表上使用ON DELETE規則

[英]PostgreSQL delete fails with ON DELETE rule on inherited table

在我的PostgreSQL 9.1數據庫中,我定義了只要刪除父表行就從子表中刪除行的規則。 一切順利,直到我介紹了繼承。 如果父(引用)表INHERITS從另一個表,我從基表中刪除,然后刪除操作成功,但該規則不會出現在所有的火-被引用的行不會被刪除。 如果我嘗試從派生表中刪除,則會收到錯誤消息:

update or delete on table "referenced" violates foreign key constraint "fk_derived_referenced" on table "derived"

父表中沒有其他行會違反外鍵:正在被刪除的行引用! 我該如何解決?

以下腳本重現了該問題:

-- Schema

CREATE TABLE base
(
  id serial NOT NULL,
  name character varying(100),
  CONSTRAINT pk_base PRIMARY KEY (id)
);

CREATE TABLE referenced
(
  id serial NOT NULL,
  value character varying(100),
  CONSTRAINT pk_referenced PRIMARY KEY (id)
);

CREATE TABLE derived
(
  referenced_id integer,
  CONSTRAINT pk_derived PRIMARY KEY (id),
  CONSTRAINT fk_derived_referenced FOREIGN KEY (referenced_id) REFERENCES referenced (id)
)
INHERITS (base);

-- The rule

CREATE OR REPLACE RULE rl_derived_delete_referenced
AS ON DELETE TO derived DO ALSO
DELETE FROM referenced r WHERE r.id = old.referenced_id;

-- Some test data

INSERT INTO referenced (id, value)
VALUES (1, 'referenced 1');

INSERT INTO derived (id, name, referenced_id)
VALUES (2, 'derived 2', 1);

-- Delete from base - deletes the "base" and "derived" rows, but not "referenced"
--DELETE FROM base
--WHERE id = 2;

-- Delete from derived - fails with:
-- update or delete on table "referenced" violates foreign key constraint "fk_derived_referenced" on table "derived"
DELETE FROM derived
WHERE id = 2

正如我在評論中所說,這似乎是一種不尋常的做事方式。 但是您可以使它與延遲約束一起工作。

CREATE TABLE derived
(
  referenced_id integer,
  CONSTRAINT pk_derived PRIMARY KEY (id),
  CONSTRAINT fk_derived_referenced FOREIGN KEY (referenced_id) 
    REFERENCES referenced (id) DEFERRABLE INITIALLY DEFERRED
)
INHERITS (base);

PostgreSQL文檔“規則與觸發器” ,例如

使用觸發器可以完成的許多事情也可以使用PostgreSQL規則系統來實現。 規則無法實現的事情之一是某些約束,尤其是外鍵。

但是我不清楚這個特定限制是您遇到的問題。

另外,您需要檢查其他記錄是否仍在引用要刪除的行。 我添加了一個測試派生記錄#3,它指向相同的#1參考記錄。

-- The rule    
CREATE OR REPLACE RULE rl_derived_delete_referenced
AS ON DELETE TO tmp.derived DO ALSO (
    DELETE FROM tmp.referenced re_del
    WHERE re_del.id = OLD.referenced_id
    AND NOT EXISTS ( SELECT * FROM tmp.derived other
        WHERE other.referenced_id = re_del.id
        AND other.id <> OLD.id )
        ;
    );

-- Some test data

INSERT INTO tmp.referenced (id, value)
VALUES (1, 'referenced 1');

-- EXPLAIN ANALYZE
INSERT INTO tmp.derived (id, name, referenced_id)
VALUES (2, 'derived 2', 1); 

INSERT INTO tmp.derived (id, name, referenced_id)
VALUES (3, 'derived 3', 1);

-- Delete from base - deletes the "base" and "derived" rows, but not "referenced"
--DELETE FROM base
--WHERE id = 2;

-- Delete from derived - fails with:
-- update or delete on table "referenced" violates foreign key constraint "fk_derived_referenced" on table "derived"

EXPLAIN ANALYZE
DELETE FROM tmp.derived
WHERE id = 2
    ;

SELECT * FROM tmp.base;
SELECT * FROM tmp.derived;
SELECT * FROM tmp.referenced;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM