Postgresql 引用继承表的外键

Postgresql 引用继承表的外键,postgresql,postgresql-9.2,Postgresql,Postgresql 9.2,我有以下表格: CREATE TABLE mail ( id serial, parent_mail_id integer, ... PRIMARY KEY (id), FOREIGN KEY (parent_mail_id) REFERENCES mail(id), ... ); CREATE TABLE incoming ( from_contact_id integer NOT NULL REFERENCES contact(id

我有以下表格:

CREATE TABLE mail (
    id serial,
    parent_mail_id integer,
    ...

    PRIMARY KEY (id),
    FOREIGN KEY (parent_mail_id) REFERENCES mail(id),
    ...
);

CREATE TABLE incoming (
    from_contact_id integer NOT NULL REFERENCES contact(id),
    ...
    PRIMARY KEY (id),
    ---> FOREIGN KEY (parent_mail_id) REFERENCES mail(id), <---
    ...
) INHERITS(mail);

CREATE TABLE outgoing (
    from_user_id integer NOT NULL REFERENCES "user"(id),
    ...  
    PRIMARY KEY (id),
    --> FOREIGN KEY (parent_mail_id) REFERENCES mail(id), <--
    ...
) INHERITS(mail);
创建表邮件(
id序列号,
父项\u邮件\u id整数,
...
主键(id),
外键(父邮件id)引用邮件(id),
...
);
创建传入表(
from_contact_id整数非空引用contact(id),
...
主键(id),
--->外键(父邮件id)引用邮件(id),外键(父邮件id)引用邮件(id),:

继承特性的一个严重限制是索引 (包括唯一约束)和外键约束仅适用 对于单个表,而不是它们的继承子表。对于 外键约束的参照侧和参照侧。 因此,在上述示例中:

如果我们将cities.name声明为唯一的或主键,这不会阻止capitals表中包含带有名称的行 复制城市中的行。默认情况下,这些重复行 显示在城市查询中。事实上,默认情况下,大写字母 完全没有唯一约束,因此可能包含多行 使用相同的名称。您可以为大写字母添加唯一的约束,但是 与城市相比,这并不能防止重复

类似地,如果指定cities.name引用其他表,则此约束不会自动传播到 大写。在这种情况下,您可以通过手动添加 对大写字母的引用相同

指定另一个表的列引用城市(名称)将允许另一个表包含城市名称,但不包含大写字母 名字。这个案子没有好的解决办法

这些缺陷可能会在将来的版本中修复,但是 与此同时,在决定是否 继承对您的应用程序很有用。


这并不是一个真正的解决方法,因此可能会将邮件设为非继承表,然后将传入和传出的列分别作为各自的额外列,并将邮件id作为主键和外键。例如,您可以创建一个视图“作为邮件传出”内部联接“传出”列。

您可以使用约束触发器

CREATE OR REPLACE FUNCTION mail_ref_trigger()
  RETURNS trigger AS
$BODY$
DECLARE
BEGIN
    IF NOT EXISTS (
        SELECT 1 FROM mail WHERE id = NEW.parent_mail_id
        ) THEN
        RAISE foreign_key_violation USING MESSAGE = FORMAT('Referenced mail id not found, mail_id:%s', NEW.parent_mail_id);
    END IF;
    RETURN NEW;
END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;

CREATE CONSTRAINT TRIGGER mail_fkey_trigger
    AFTER UPDATE OR INSERT ON incoming
    DEFERRABLE
    FOR EACH ROW EXECUTE PROCEDURE mail_ref_trigger();