Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/80.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/database/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 我应该暂时禁用外键约束吗?怎么用?_Sql_Database_Postgresql_Foreign Keys - Fatal编程技术网

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
外键约束将限制删除

我的问题分为两部分:

  • 暂时禁用第二个外键是我唯一的选择吗
  • 如果是这样的话,那么在PostgreSQL中我该怎么做呢
  • 实际上,你创造了一个与规则相矛盾的竞赛条件

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

    我发现在
    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 from
    pg\u约束来判断)。我从你的小提琴上复制了代码,它在本地工作,所以这是实现我目标的一种方式,但我认为它工作的原因可能不是oid更大。我得试试推迟的事。我不明白你回答的最后一部分:
    tenant\u id
    customer\u id
    都有
    notnull
    约束。啊!现在我明白你的意思了!第二个SQLFIDLE中的场景不会发生在我的系统中,因为不同的租户不能共享一个共同的客户,即租户定义了一个范围。我不该不提这事。我想最好不要依赖未记录的行为,正如您所说,因此我将暂时禁用约束或使用触发器或规则实现解决方案,我还没有决定。无论如何,非常感谢您的帮助。顺便说一句,我在Postgres手册的“创建表”部分读到,“除了无操作检查之外的引用操作不能延迟,即使约束声明为可延迟。”@克拉帕斯:我意识到了这一点,并使用
    无操作运行了我的测试,该操作可以很好地替代
    限制
    ,但正如我的回答中所记录的那样无效。为什么删除了您的评论?现在这是一段毫无意义的独白。
    ALTER TABLE task DISABLE trigger ALL;