Sql 我应该暂时禁用外键约束吗?怎么用?
我有两张桌子:Sql 我应该暂时禁用外键约束吗?怎么用?,sql,database,postgresql,foreign-keys,Sql,Database,Postgresql,Foreign Keys,我有两张桌子: 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 (他们的专栏比这多得多,但其余的与问题
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
(他们的专栏比这多得多,但其余的与问题无关。)
问题是,我想在删除一个任务
的租户人员
时级联删除该任务。但是当租户和客户是同一个人时,customer\u id
外键约束将限制删除
我的问题分为两部分:
CREATE TABLE
脚本中首先出现的FK约束是这场比赛的赢家。如果删除级联上的先出现,则删除级联;如果删除限制上的先出现,则操作中止
考虑一下这个演示
这似乎与目录表中较小的oid
相关:
但你的反馈表明,这不是原因。也许决定比赛。不管怎样,只要它没有被记录下来,你就不能依靠它在下一个主要版本中保持这种状态。可能值得在pgsql上发布一个问题-general@postgresql.org.
独立于此,您需要考虑其他行:即使<代码>级联< /COD>将在<代码>任务中进行一行,它同时具有<代码> TANTANGIDID<代码>和<代码> Cuuler-SudioID <代码>指向“代码>人<代码>,如果任何行只有
customer\u id
引用person
,则仍将受到限制
另一个例子证明了这一点
如何禁用约束?
你最好的办法是放弃并重新创建它。在事务内部执行所有操作,以确保不会破坏引用完整性
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
中获取它。使用显式约束名称开头可能更容易:
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约束
其他的选择是用或来实施你的制度。这可以很好地工作,但它们不像外键那样严格地强制执行。table person是自引用的吗?还是我误会了?@Frederic是的,我忘了。。。我已经更新了问题accordingly@clapas,当id=tenant\u id时出现问题?或任何其他应在级联上删除的寄存器?对不起,我真的不太清楚Postgres,但是Ms sql server也有类似的问题,sql server不允许在自引用时设置删除级联。。。我做了一个cte来获取所有将在cascade中删除的regs,并在同一个delete语句中删除所有regs。。这样,FK未限制原因确实注册将一起删除…请澄清person.tenant\u id
的角色。似乎与这个问题无关?另外,你提到问题的第一部分和第二部分,我无法确定。我只看到一个问题。并声明正在使用的Postgres版本。如果要级联删除,为什么在客户id
外键约束中有on delete restrict
?啊,我明白了,没关系。我已经尝试过类似的东西,但由于某种原因,它没有起作用。我删除了tenant\u id
外键,然后重新创建了它,所以它的oid更大(我可以通过您指出的select frompg\u约束来判断)。我从你的小提琴上复制了代码,它在本地工作,所以这是实现我目标的一种方式,但我认为它工作的原因可能不是oid更大。我得试试推迟的事。我不明白你回答的最后一部分:tenant\u id
和customer\u id
都有notnull
约束。啊!现在我明白你的意思了!第二个SQLFIDLE中的场景不会发生在我的系统中,因为不同的租户不能共享一个共同的客户,即租户定义了一个范围。我不该不提这事。我想最好不要依赖未记录的行为,正如您所说,因此我将暂时禁用约束或使用触发器或规则实现解决方案,我还没有决定。无论如何,非常感谢您的帮助。顺便说一句,我在Postgres手册的“创建表”部分读到,“除了无操作检查之外的引用操作不能延迟,即使约束声明为可延迟。”@克拉帕斯:我意识到了这一点,并使用无操作运行了我的测试,该操作可以很好地替代限制
,但正如我的回答中所记录的那样无效。为什么删除了您的评论?现在这是一段毫无意义的独白。
ALTER TABLE task DISABLE trigger ALL;