简体   繁体   English

删除 PostgreSQL 中带有外键的行

[英]Delete rows with foreign key in PostgreSQL

I would like to delete rows which contain a foreign key, but when I try something like this:我想删除包含外键的行,但是当我尝试这样的事情时:

DELETE FROM osoby WHERE id_osoby='1'

I get this statement:我得到这个声明:

ERROR: update or delete on table "osoby" violates foreign key constraint "kontakty_ibfk_1" on table "kontakty" DETAIL: Key (id_osoby)=(1) is still referenced from table "kontakty".错误:表“osoby”上的更新或删除违反了表“kontakty”上的外键约束“kontakty_ibfk_1”详细信息:键(id_osoby)=(1)仍然从表“kontakty”中引用。

How can I delete these rows?如何删除这些行?

To automate this, you could define the foreign key constraint with ON DELETE CASCADE .要自动执行此操作,您可以使用ON DELETE CASCADE定义外键约束。
I quote the the manual for foreign key constraints :我引用了外键约束的手册

CASCADE specifies that when a referenced row is deleted, row(s) referencing it should be automatically deleted as well. CASCADE指定当删除引用的行时,引用它的行也应自动删除。

Look up the current FK definition like this:像这样查找当前的 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';

Then add or modify the ON DELETE ... part to ON DELETE CASCADE (preserving everything else as is) in a statement like:然后在如下语句中添加或修改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;

There is no ALTER CONSTRAINT command.没有ALTER CONSTRAINT命令。 Drop and recreate the constraint in a single ALTER TABLE statement to avoid possible race conditions with concurrent write access.在单个ALTER TABLE语句中删除并重新创建约束,以避免并发写访问时可能出现的竞争条件。

You need the privileges to do so, obviously.显然,您需要特权才能这样做。 The operation takes an ACCESS EXCLUSIVE lock on table kontakty and a SHARE ROW EXCLUSIVE lock on table osoby .该操作需要一个ACCESS EXCLUSIVE上表锁kontaktySHARE ROW EXCLUSIVE上表锁osoby

If you can't ALTER the table, then deleting by hand (once) or by trigger BEFORE DELETE (every time) are the remaining options.如果您不能ALTER表,那么手动删除(一次)或通过触发器BEFORE DELETE (每次) BEFORE DELETE是剩下的选项。

You can't delete a foreign key if it still references another table.如果外键仍然引用另一个表,则不能删除它。 First delete the reference先删除引用

delete from kontakty
where id_osoby = 1;

DELETE FROM osoby 
WHERE id_osoby = 1;

One should not recommend this as a general solution, but for one-off deletion of rows in a database that is not in production or in active use, you may be able to temporarily disable triggers on the tables in question.不应将其推荐为通用解决方案,但对于一次性删除不在生产中或未在使用中的数据库中的行,您可以暂时禁用相关表上的触发器。

In my case, I'm in development mode and have a couple of tables that reference one another via foreign keys.就我而言,我处于开发模式并且有几个表通过外键相互引用。 Thus, deleting their contents isn't quite as simple as removing all of the rows from one table before the other.因此,删除它们的内容并不像从一个表中删除另一个表中的所有行那么简单。 So, for me, it worked fine to delete their contents as follows:所以,对我来说,删除它们的内容很好,如下所示:

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;

You should be able to add WHERE clauses as desired, of course with care to avoid undermining the integrity of the database.您应该能够根据需要添加 WHERE 子句,当然要小心避免破坏数据库的完整性。

There's some good, related discussion at http://www.openscope.net/2012/08/23/subverting-foreign-key-constraints-in-postgres-or-mysql/http://www.openscope.net/2012/08/23/subverting-foreign-key-constraints-in-postgres-or-mysql/ 上有一些很好的相关讨论

It's been a while since this question was asked, hope can help.问这个问题已经有一段时间了,希望能有所帮助。 Because you can not change or alter the db structure, you can do this.因为您无法更改或更改 db 结构,所以您可以这样做。 according the postgresql docs .根据 postgresql 文档

TRUNCATE -- empty a table or set of tables. TRUNCATE -- 清空一个表或一组表。

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

Description描述

TRUNCATE quickly removes all rows from a set of tables. TRUNCATE 从一组表中快速删除所有行。 It has the same effect as an unqualified DELETE on each table, but since it does not actually scan the tables it is faster.它与对每个表的非限定 DELETE 具有相同的效果,但由于它实际上并不扫描表,因此速度更快。 Furthermore, it reclaims disk space immediately, rather than requiring a subsequent VACUUM operation.此外,它会立即回收磁盘空间,而不需要后续的 VACUUM 操作。 This is most useful on large tables.这在大表上最有用。


Truncate the table othertable, and cascade to any tables that reference othertable via foreign-key constraints:截断表 othertable,并通过外键约束级联到引用 othertable 的任何表:

TRUNCATE othertable CASCADE;

The same, and also reset any associated sequence generators:相同,并且还重置任何关联的序列生成器:

TRUNCATE bigtable, fattable RESTART IDENTITY;

Truncate and reset any associated sequence generators:截断和重置任何关联的序列生成器:

TRUNCATE revinfo RESTART IDENTITY CASCADE ;

It means that in table kontakty you have a row referencing the row in osoby you want to delete.这意味着在kontakty表中有一行引用了osoby要删除的行。 You have do delete that row first or set a cascade delete on the relation between tables.您必须先删除该行或在表之间的关系上设置级联删除。

Powodzenia!波沃泽尼亚!

One can achieve this by issueing an extra SQL script that deletes the records related via the FK .可以通过发出一个额外的 SQL 脚本来删除通过FK相关的记录来实现这一点。

For this, using subselect in WHERE clause of a DELETE command can simply do what is needed.为此,在DELETE命令的WHERE子句中使用 subselect 可以简单地完成所需的操作。

Something similar to:类似于:

DELETE FROM kontakty 
    WHERE fk_column_from_kontakty_matching_id_osoby IN (
        SELECT id_osoby FROM osoby WHERE id_osoby = '1'
    );


DELETE FROM osoby WHERE id_osoby = '1';
  • the example assumes the FK column from kontakty matching osoby.id_osoby is called fk_column_from_kontakty_matching_id_osoby as it cannot be interpolated from the error message provided该示例假定来自kontakty匹配osoby.id_osobyFK列称为fk_column_from_kontakty_matching_id_osoby ,因为它无法从提供的错误消息中插值
  • For the case of OP's the query could by simplified a lot, but I have decided to leave it like this for it demonstrates accomplishing more complex scenarios对于 OP 的情况,查询可以简化很多,但我决定这样保留它,因为它演示了完成更复杂的场景
  • This approach is quite useful for SQL migrations, where one cannot depend on an assigned id and where id s cannot be easily fetched first and acted upon later.这种方法对于 SQL 迁移非常有用,在这种迁移中,人们不能依赖分配的id ,并且id不能先轻松获取并在以后采取行动。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM