我有以下表格:
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);
incoming
和outgoing
继承自mail
并再次定义其外键(和主键),因为它们不会自动继承。
问题是:
如果我要插入incoming
邮件,则无法从outgoing
表引用它,因为外键仅适用于超级表(mails
)。< / p>
是否有解决方法?
答案 0 :(得分:4)
继承功能的一个严重限制是索引 (包括唯一约束)和外键约束仅适用 单个表,而不是他们的继承子。这是真的 外键约束的引用和引用方。 因此,就上述例子而言:
如果我们将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();