在PostgreSQL中删除带有外键的行

时间:2013-01-06 12:27:34

标签: sql postgresql foreign-keys cascading-deletes

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

DELETE FROM osoby WHERE id_osoby='1'

我得到这样的声明:

  

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

如何删除这些行?

5 个答案:

答案 0 :(得分:59)

要自动执行此操作,您可以使用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上的kontakty锁定以及对表SHARE ROW EXCLUSIVE的{​​{1}}锁定。

如果您不能osoby表格,则手动删除(一次)或触发ALTER(每次)都是其余选项。

答案 1 :(得分:30)

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

delete from kontakty
where id_osoby = 1;

DELETE FROM osoby 
WHERE id_osoby = 1;

答案 2 :(得分: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/

进行了一些很好的相关讨论

答案 3 :(得分: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 ;

答案 4 :(得分:6)

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

Powodzenia!