114

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

DELETE FROM osoby WHERE id_osoby='1'

我得到这个声明:

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

如何删除这些行?

4

5 回答 5

129

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

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

像这样查找当前的 FK 定义:

SELECT pg_get_constraintdef(oid) AS constraint_def
FROM   pg_constraint
WHERE  conrelid = 'public.kontakty'::regclass  -- assuming public 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在 table上锁定kontaktySHARE ROW EXCLUSIVE在 table 上锁定osoby

如果您不能ALTER使用该表,则剩下的选项是手动(一次)或触发器BEFORE DELETE(每次)删除。

于 2013-01-06T12:55:45.417 回答
43

如果外键仍然引用另一个表,则不能删除它。首先删除引用

delete from kontakty
where id_osoby = 1;

DELETE FROM osoby 
WHERE id_osoby = 1;
于 2013-01-06T12:32:01.523 回答
42

不应将此作为一般解决方案推荐,但对于一次性删除数据库中非生产或活动使用的行,您可以暂时禁用相关表上的触发器。

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

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

于 2016-03-09T01:34:24.063 回答
30

很久没问这个问题了,希望能帮到你。因为您无法更改或更改 db 结构,所以您可以这样做。根据 postgresql文档

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

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

描述

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


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

TRUNCATE othertable CASCADE;

同样,也重置任何关联的序列生成器:

TRUNCATE bigtable, fattable RESTART IDENTITY;

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

TRUNCATE revinfo RESTART IDENTITY CASCADE ;
于 2016-10-18T14:19:35.947 回答
8

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

波沃兹尼亚!

于 2013-01-06T12:30:31.807 回答