繁体   English   中英

我应该暂时禁用外键约束吗?怎么样?

[英]Should I temporarily disable foreign key constraints? How?

我有两张桌子:

person:
    id serial primary key,
    name varchar(64) not null

task:
    tenant_id   integer not null references person (id) on delete cascade,
    customer_id integer not null references person (id) on delete restrict

(他们有比这更多的列,但其余的与问题无关。)

问题是,我想级联删除task时,其承租人person将被删除。 但是当租户和客户是同一个人时, customer_id外键约束将限制删除。

我的问题有两个部分:

  1. 暂时禁用第二个外键是我唯一的选择吗?
  2. 如果是这样,那么我如何在PostgreSQL中做到这一点?

实际上你创造了一个矛盾规则的竞争条件

我的第一个冲动是检查DEFERRED约束是否有帮助。 但它没有任何区别是有道理的

我发现CREATE TABLE脚本中首先出现的FK约束是这场比赛的胜利者。 如果ON DELETE CASCADE首先出现,则删除是级联的,如果ON DELETE RESTRICT先出现,则操作中止。

考虑一下SQL Fiddle的演示。

这似乎与目录表pg_constraint较小的oid相关:

SELECT oid, * FROM pg_constraint WHERE conrelid = 'task'::regclass

但是你的反馈表明,这不是原因。 也许pg_attribute.attnum决定比赛。 无论哪种方式,只要它没有记录的行为,你就不能依赖它在下一个主要版本中保持这种状态。 可能值得在pgsql-general@postgresql.org上发布一个问题。

独立于所有这些,你需要考虑其他行:即使CASCADE在一个同时具有tenant_idcustomer_id指向某person task中的行中,如果任何行只有customer_id引用person ,它仍将受到限制。
另一个SQL小提琴演示案例。

如何禁用约束?

你最好的选择是放弃并重新创建它。 在事务中完成所有操作以确保您不会破坏参照完整性。

BEGIN;

ALTER TABLE task DROP CONSTRAINT task_customer_id_fkey;

DELETE FROM person WHERE id = 3;

ALTER TABLE task ADD CONSTRAINT task_customer_id_fkey
FOREIGN KEY (customer_id) REFERENCES person (id) ON DELETE RESTRICT;

COMMIT;

这将独占锁定表,不适合在多用户环境中进行常规使用。

我怎么知道约束的名字 我从pg_constraint演示的pg_constraint了它。 可能更容易使用显式约束名称开头:

CREATE TEMP TABLE task (
    customer_id integer NOT NULL
   ,tenant_id integer NOT NULL REFERENCES person (id) ON DELETE CASCADE
   ,CONSTRAINT task_customer_id_fkey FOREIGN KEY (customer_id)
    REFERENCES person (id) ON DELETE RESTRICT
);

还有

ALTER TABLE task DISABLE trigger ALL;

更多在手册中 但这会禁用所有触发器。 我没有运气试图仅禁用系统创建的触发器来实现单个FK约束。

其他替代方案是通过触发器规则实施您的制度。 这样可以正常工作,但这些并不像外键那样严格执行。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM