web-dev-qa-db-de.com

Löschen Sie Zeilen mit Fremdschlüssel in PostgreSQL

Ich möchte Zeilen löschen, die einen Fremdschlüssel enthalten, aber wenn ich so etwas versuche:

DELETE FROM osoby WHERE id_osoby='1'

Ich bekomme diese Aussage:

FEHLER: Aktualisierung oder Löschen der Tabelle "osoby" verstößt gegen die Fremdschlüsseleinschränkung "kontakty_ibfk_1" für die Tabelle "kontakty".

Wie kann ich diese Zeilen löschen?

55
Michal Loksik

Um dies zu automatisieren, können Sie die Fremdschlüsselbedingung mit ON DELETE CASCADE Definieren.
Ich zitiere das das Handbuch der Fremdschlüsseleinschränkungen :

CASCADE gibt an, dass beim Löschen einer referenzierten Zeile auch die darauf verweisenden Zeilen automatisch gelöscht werden sollen.

Suchen Sie die aktuelle FK-Definition wie folgt:

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

Fügen Sie dann den Teil ON DELETE ... Zu ON DELETE CASCADE Hinzu oder ändern Sie ihn in einer Anweisung wie folgt:

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

Da es keine ALTER CONSTRAINT - Syntax gibt, löschen Sie die Einschränkung und erstellen Sie sie in einer einzelnen ALTER TABLE - Anweisung neu. Das vermeidet mögliche Rennbedingungen bei gleichzeitigem Schreibzugriff.

Dazu benötigen Sie natürlich die erforderlichen Berechtigungen. Die Operation benötigt eine ACCESS EXCLUSIVE - Sperre für Tabelle kontakty und eine SHARE ROW EXCLUSIVE - Sperre für Tabelle osoby.

Wenn Sie die Tabelle nicht ALTER können, sind die verbleibenden Optionen das Löschen von Hand (einmal) oder durch Auslösen von BEFORE DELETE (Jedes Mal).

66

Sie können einen Fremdschlüssel nicht löschen, wenn er noch auf eine andere Tabelle verweist. Löschen Sie zuerst die Referenz

delete from kontakty
where id_osoby = 1;

DELETE FROM osoby 
WHERE id_osoby = 1;
31
juergen d

Dies sollte nicht als allgemeine Lösung empfohlen werden, aber zum einmaligen Löschen von Zeilen in einer Datenbank, die sich nicht in Produktion befindet oder aktiv verwendet wird, können Sie möglicherweise Trigger für die betreffenden Tabellen vorübergehend deaktivieren.

In meinem Fall bin ich im Entwicklungsmodus und habe ein paar Tabellen, die über Fremdschlüssel aufeinander verweisen. Das Löschen des Inhalts ist daher nicht so einfach wie das Entfernen aller Zeilen aus einer Tabelle vor der anderen. Für mich hat es also gut funktioniert, die Inhalte wie folgt zu löschen:

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;

Sie sollten in der Lage sein, WHERE-Klauseln wie gewünscht hinzuzufügen, um die Integrität der Datenbank nicht zu gefährden.

Es gibt einige gute, verwandte Diskussionen unter http://www.openscope.net/2012/08/23/subverting-foreign-key-constraints-in-postgres-or-mysql/

16
Andrew Basile

Es ist schon eine Weile her, seit diese Frage gestellt wurde, Hoffnung kann helfen. Da Sie die Datenbankstruktur nicht ändern können, können Sie dies tun. laut postgresql docs .

[~ # ~] abschneiden [~ # ~] - Eine Tabelle oder eine Gruppe von Tabellen leeren.

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

Beschreibung

TRUNCATE entfernt schnell alle Zeilen aus einer Reihe von Tabellen. Dies hat den gleichen Effekt wie ein nicht qualifiziertes DELETE für jede Tabelle, ist jedoch schneller, da die Tabellen nicht gescannt werden. Darüber hinaus wird sofort Speicherplatz freigegeben, anstatt dass ein nachfolgender VACUUM-Vorgang erforderlich ist. Dies ist am nützlichsten bei großen Tabellen.


Kürzen Sie die Tabelle othertable und kaskadieren Sie sie auf alle Tabellen, die über Fremdschlüsseleinschränkungen auf othertable verweisen:

TRUNCATE othertable CASCADE;

Dies gilt auch für das Zurücksetzen aller zugeordneten Sequenzgeneratoren:

TRUNCATE bigtable, fattable RESTART IDENTITY;

Kürzen Sie alle zugehörigen Sequenzgeneratoren und setzen Sie sie zurück:

TRUNCATE revinfo RESTART IDENTITY CASCADE ;
10
OJVM

Dies bedeutet, dass Sie in Tabelle kontakty eine Zeile haben, die auf die Zeile in osoby verweist, die Sie löschen möchten. Sie müssen diese Zeile zuerst löschen oder eine Kaskadenlöschung für die Beziehung zwischen Tabellen festlegen.

Powodzenia!

6
zibi