Postgresql 是否可以防止删除,但不能使用外键插入?

Postgresql 是否可以防止删除,但不能使用外键插入?,postgresql,referential-integrity,Postgresql,Referential Integrity,我有两个表,我想用一个单列外键链接它们。一种正常的父子关系。我试图解决的问题是,系统的本质是,孩子可以在父母存在之前到达,孩子知道父母的id是什么 我不想延迟孩子的插入等待家长的到来,速度很重要。但我确实需要一些引用完整性——如果子对象存在,我不希望能够删除父对象 我假设我不能用Postgresql中的常规外键实现这一点?解决方案是编写某种触发器吗?您可以使用延迟约束来完成此操作 创建表子父项\u id整数引用父项可延迟初始立即; 然后,您可以在事务中使用来临时推迟约束,如下所示: 启动交易;

我有两个表,我想用一个单列外键链接它们。一种正常的父子关系。我试图解决的问题是,系统的本质是,孩子可以在父母存在之前到达,孩子知道父母的id是什么

我不想延迟孩子的插入等待家长的到来,速度很重要。但我确实需要一些引用完整性——如果子对象存在,我不希望能够删除父对象


我假设我不能用Postgresql中的常规外键实现这一点?解决方案是编写某种触发器吗?

您可以使用延迟约束来完成此操作

创建表子父项\u id整数引用父项可延迟初始立即; 然后,您可以在事务中使用来临时推迟约束,如下所示:

启动交易; 设置所有延迟的约束条件; -你的插页在这里- 犯罪
如果在同一数据库事务中创建父事务和子事务,并且无法控制插入顺序,那么正确的方法是使用延迟约束,正如@Ragesh所建议的那样

否则,您猜对了:解决方案是编写某种触发器

Postgres中的外键约束只不过是一对触发器,具体来说:

插入或更新子项的FK时的触发器,用于检查父项是否存在,以及获取密钥共享锁以确保父项不会在提交之前消失 删除或更新父PK时的触发器,以检查其是否没有子PK 在这种情况下,您只需要父触发器,而不需要子触发器。幸运的是,你自己写很简单。像这样的东西应该可以做到:

create table parent (id int primary key);
create table child (id int primary key, parent_id int);

create function trg_parent_fk_check() returns trigger language plpgsql as $$
begin
  if exists(select 1 from child where parent_id = old.id) then
    raise foreign_key_violation using
      message = 'parent.id=' || old.id || ' is still referenced by child.parent_id';
  end if;
end
$$;

create trigger trg_parent_fk_check_del
after delete on parent
for each row
execute function trg_parent_fk_check();

/* You probably shouldn't be modifying primary keys, but just in case... */
create trigger trg_parent_fk_check_upd
after update of id on parent
for each row
when (old.id <> new.id)
execute function trg_parent_fk_check();

当然,这种方法允许孩子到达,但家长没有。您可能希望包括一些预定的过程来查找和删除孤立记录。

如果子记录首先到达,您可能应该始终将其插入父记录,然后当父记录“到达”时,再执行一次更新。如果两次插入不是在一个事务中进行的,它们可能相隔几秒钟。此解决方案仍然有效吗?约束只能在事务中延迟。如果不是在单个事务中执行所有插入,则此解决方案将不起作用。两个插入不在同一事务中