在PostgreSQL中删除带有外键的行


77

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

DELETE FROM osoby WHERE id_osoby='1'

我得到以下声明:

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

如何删除这些行?


3
检查这个问题,以及上删除级联;)这是很好的在你的表中有这些设置,但..当creating foreign keys我们add parent then child。因此,当删除我们时delete child and then parent;)
bonCodigo

Answers:


90

要自动执行此操作,可以使用定义外键约束ON DELETE CASCADE
我引用外键约束手册

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剩下的选项是手动(一次)或触发器(每次)删除。


4
我们尚未使用ON创建表DELETE CASCADE。我无法更改表的结构。有没有一种方法可以自动删除外键?或者我们要遵循@juergen d建议的方式
वरुण

2
@Varun:如果您不能ALTER在表中添加带有的FK ON DELETE CASCADE,则BEFORE DELETE剩下的选项是手动(一次)或触发器(每次)删除。
Erwin Brandstetter

很酷,所以答案是ON DELETE CASCADE在create语句中使用外键将其添加到列中。
425nesp

1
@ 425nesp:我添加了明确的说明。
欧文·布兰德斯特

就我而言,我需要DDL来查看确切的名称约束,在这种情况下,它将是\d kontakty
marquicus

36

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

delete from kontakty
where id_osoby = 1;

DELETE FROM osoby 
WHERE id_osoby = 1;

28

不应该将其推荐为一种通用解决方案,但是要一次性删除不在生产环境中或正在使用中的数据库中的行,则可以暂时禁用有关表的触发器。

就我而言,我处于开发模式,并且有几个表通过外键相互引用。因此,删除它们的内容并不像从一个表中删除所有行先于另一表那样简单。因此,对我来说,按如下所示删除它们的内容效果很好:

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/中有一些很好的相关讨论


17

提出这个问题已经有一段时间了,希望能有所帮助。因为您不能更改或更改db结构,所以可以执行此操作。根据PostgreSQL文档

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

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

描述

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


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

TRUNCATE othertable CASCADE;

相同,并重置所有关联的序列生成器:

TRUNCATE bigtable, fattable RESTART IDENTITY;

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

TRUNCATE revinfo RESTART IDENTITY CASCADE ;

不错,非常有用。
setshaft

5

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

Powodzenia!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.