外键引用继承表

时间:2013-08-02 18:13:32

标签: 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),
    ...
    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);

incomingoutgoing继承自mail并再次定义其外键(和主键),因为它们不会自动继承。

问题是:

如果我要插入incoming邮件,则无法从outgoing表引用它,因为外键仅适用于超级表(mails)。< / p>

是否有解决方法?

2 个答案:

答案 0 :(得分:4)

PostgreSQL 9.3 docs

  

继承功能的一个严重限制是索引   (包括唯一约束)和外键约束仅适用   单个表,而不是他们的继承子。这是真的   外键约束的引用和引用方。   因此,就上述例子而言:

     

如果我们将cities.name声明为UNIQUE或PRIMARY KEY,则不会阻止大写表中包含名称的行   复制城市中的行。默认情况下,那些重复的行   显示在来自城市的查询中。事实上,默认情况下,首都会   根本没有唯一约束,因此可能包含多行   同名。您可以为大写添加唯一约束,但是   与城市相比,这不会阻止重复。

     

同样,如果我们要指定cities.name REFERENCES其他一些表,则此约束不会自动传播到   首都。在这种情况下,您可以通过手动添加来解决它   相同的REFERENCES限制为大写字母。

     

指定另一个表的列REFERENCES cities(name)将允许另一个表包含城市名称,但不包含资本   名。这种情况没有好的解决方法。

     

这些缺陷可能会在未来的某个版本中修复,但是   在此期间,需要相当谨慎才能决定是否   继承对您的应用程序很有用。

并非真正的解决方法,因此可能使邮件成为非继承表,然后将incoming_columns和outgoing_columns分别用于各自的额外列,邮件ID作为主键和外键。然后,您可以创建一个视图传出,例如邮件INNER JOIN outgoing_columns。

答案 1 :(得分:3)

您可以使用约束触发器

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