在PostgreSQL中删除带有外键的行

问题描述 投票:49回答:5

我想删除包含外键的行,但是当我尝试这样的事情时:

DELETE FROM osoby WHERE id_osoby='1'

我得到这个声明:

错误:表“osoby”上的更新或删除违反表“kontakty”上的外键约束“kontakty_ibfk_1”DETAIL:键(id_osoby)=(1)仍然从表“kontakty”引用。

如何删除这些行?

sql postgresql foreign-keys cascading-deletes
5个回答
63
投票

要自动执行此操作,您可以使用ON DELETE CASCADE定义外键约束。 我引用the manual of foreign key constraints

CASCADE指定当删除引用的行时,也应自动删除引用它的行。

查找当前的FK定义,如下所示:

SELECT pg_get_constraintdef(oid) AS constraint_def
FROM   pg_constraint
WHERE  conrelid = 'public.kontakty'::regclass  -- assuming pubic schema
AND    conname = 'kontakty_ibfk_1';

然后在如下语句中添加或修改ON DELETE ...部分到ON DELETE CASCADE(保留其他所有内容):

ALTER TABLE kontakty
   DROP CONSTRAINT kontakty_ibfk_1
 , ADD  CONSTRAINT kontakty_ibfk_1
   FOREIGN KEY (id_osoby) REFERENCES osoby (id_osoby) ON DELETE CASCADE;

由于没有ALTER CONSTRAINT语法,因此在单个ALTER TABLE语句中删除并重新创建约束。这避免了可能的并发写访问的竞争条件。

显然,你需要这样做的特权。该操作需要ACCESS EXCLUSIVE锁定表kontaktySHARE ROW EXCLUSIVE锁定表osoby

如果你不能ALTER表,然后手动(一次)或触发BEFORE DELETE(每次)删除是剩余的选项。


31
投票

如果外键仍引用另一个表,则无法删除该外键。首先删除引用

delete from kontakty
where id_osoby = 1;

DELETE FROM osoby 
WHERE id_osoby = 1;

16
投票

不应该将此建议作为一般解决方案,但是对于未生产或正在使用的数据库中的一次性删除行,您可以暂时禁用相关表上的触发器。

就我而言,我处于开发模式,有几个表通过外键相互引用。因此,删除它们的内容并不像从一个表中删除所有行之前那么简单。所以,对我来说,删除其内容的工作原理如下:

ALTER TABLE table1 DISABLE TRIGGER ALL;
ALTER TABLE table2 DISABLE TRIGGER ALL;
DELETE FROM table1;
DELETE FROM table2;
ALTER TABLE table1 ENABLE TRIGGER ALL;
ALTER TABLE table2 ENABLE TRIGGER ALL;

您应该能够根据需要添加WHERE子句,当然要小心,以避免破坏数据库的完整性。

http://www.openscope.net/2012/08/23/subverting-foreign-key-constraints-in-postgres-or-mysql/有一些很好的相关讨论


10
投票

自问这个问题以来已经有一段时间了,希望能有所帮助。因为您无法更改或更改数据库结构,所以可以执行此操作。根据postgresql docs

TRUNCATE - 清空一个表或一组表。

TRUNCATE [ TABLE ] [ ONLY ] name [ * ] [, ... ]
    [ RESTART IDENTITY | CONTINUE IDENTITY ] [ CASCADE | RESTRICT ]

描述

TRUNCATE快速删除一组表中的所有行。它与每个表上的非限定DELETE具有相同的效果,但由于它实际上不扫描表,因此速度更快。此外,它立即回收磁盘空间,而不是需要后续的VACUUM操作。这对大型表最有用。


截断表othertable,并级联到任何通过外键约束引用其他表的表:

TRUNCATE othertable CASCADE;

相同,并重置任何相关的序列生成器:

TRUNCATE bigtable, fattable RESTART IDENTITY;

截断并重置任何关联的序列生成器:

TRUNCATE revinfo RESTART IDENTITY CASCADE ;

6
投票

这意味着在表kontakty中,您有一行引用要删除的osoby中的行。您必须先删除该行,或者在表之间的关系上设置级联删除。

祝你好运!

© www.soinside.com 2019 - 2024. All rights reserved.