Wie schneide ich eine Tabelle mit eingeschränkten Fremdschlüsseln ab?


647

Warum nicht ein TRUNCATE auf mygroupArbeit? Obwohl ich habe, ON DELETE CASCADE SETbekomme ich:

ERROR 1701 (42000): kann eine Tabelle in einer Fremdschlüsselbedingung verwiesen gestutzt ( mytest. instance, Constraint instance_ibfk_1FOREIGN KEY ( GroupID) LITERATUR mytest. mygroup( ID))

drop database mytest;
create database mytest;
use mytest;

CREATE TABLE mygroup (
   ID    INT NOT NULL AUTO_INCREMENT PRIMARY KEY
) ENGINE=InnoDB;

CREATE TABLE instance (
   ID           INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
   GroupID      INT NOT NULL,
   DateTime     DATETIME DEFAULT NULL,

   FOREIGN KEY  (GroupID) REFERENCES mygroup(ID) ON DELETE CASCADE,
   UNIQUE(GroupID)
) ENGINE=InnoDB;

Antworten:


997

Sie können keine TRUNCATETabelle mit FK-Einschränkungen anwenden ( TRUNCATEist nicht dasselbe wie DELETE).

Verwenden Sie eine dieser Lösungen, um dies zu umgehen. Beide bergen das Risiko einer Beschädigung der Datenintegrität.

Option 1:

  1. Entfernen Sie Einschränkungen
  2. Ausführen TRUNCATE
  3. Löschen Sie manuell die Zeilen, die jetzt auf nirgendwo verweisen
  4. Erstellen Sie Einschränkungen

Option 2: vorgeschlagen von user447951 in ihrer Antwort

SET FOREIGN_KEY_CHECKS = 0; 
TRUNCATE table $table_name; 
SET FOREIGN_KEY_CHECKS = 1;

46
@barjonah: Tatsächlich kann die Datenintegrität beeinträchtigt werden (siehe stackoverflow.com/questions/5452760/… ). Was Sie in der realen Welt "Licht" nennen, wird als schlechte Praxis angesehen. PS: Danke für die Abwertung
zerkms

1
Hier ist ein sehr guter Weg, um verwaiste Fremdschlüssel zu finden (Datenintegrität wiederherstellen) http://stackoverflow.com/a/12085689/997776
SandorRacz

Fremdschlüssel vor dem Abschneiden zu
Dung

2
@Dung Deaktivieren von Fremdschlüsselprüfungen ist nur im Entwicklungszeitraum zulässig. Es bricht alle bestehenden Beziehungen. zerkms hat 100% Recht mit der Datenintegrität. Sie können Fremdschlüsselprüfungen für eine funktionierende Datenbank nur deaktivieren, wenn Sie vorhaben, sie vollständig (oder zumindest alle zugehörigen Tabellen) zu leeren
NoobishPro

1
@Kamlesh es ist nicht meine Lösung, ich habe geraten, es nicht so barbarisch zu machen.
Zerkms

1307

Ja, du kannst:

SET FOREIGN_KEY_CHECKS = 0;

TRUNCATE table1;
TRUNCATE table2;

SET FOREIGN_KEY_CHECKS = 1;

Mit diesen Anweisungen riskieren Sie, Zeilen in Ihre Tabellen aufzunehmen, die den FOREIGN KEYEinschränkungen nicht entsprechen.


30
Müssen wir SET FOREIGN_KEY_CHECKS = 1 setzen? danach wieder?
vinc3m1

77
Nein, tust du nicht. Die Einstellung ist nur während der Verbindung gültig. Sobald Sie die Verbindung trennen, wird die nächste Verbindung auf 1 zurückgesetzt.
Der Pellmeister

7
Dies gilt nicht für das Ereignis 'ON DELETE' in der Tabelle, auf die verwiesen wird. Dies ist also keine vollständige Antwort.
Omer Sabic

5
Bei Verwendung in PHPMYADMIN funktioniert dies nur, wenn Sie alle Transaktionen in demselben SQL-Fenster verwenden (durch a getrennt ;). Dies liegt daran, dass jeder neue Web-SQL-Aufruf den FOREIGN_KEY_CHECKS
Wert

1
Hier ist eine sehr gute Möglichkeit, verwaiste Fremdschlüssel zu finden (Datenintegrität wiederherstellen), falls Sie interessiert sind http://stackoverflow.com/a/12085689/997776
SandorRacz

173

Ich würde es einfach machen mit:

DELETE FROM mytest.instance;
ALTER TABLE mytest.instance AUTO_INCREMENT = 1;

5
Clever. Wenn Sie trotzdem alle Datensätze löschen möchten, können Sie das automatische Inkrement auch zurücksetzen.
Winkbrace

6
Dies ist offensichtlich der beste Weg, dies zu tun. Kein Risiko, Einschränkungen zu verlieren, einfach löschen. Es ist erwähnenswert, dass DELETEdie Leistung langsamer ist als TRUNCATE. Da diese Aktion jedoch normalerweise nur selten ausgeführt wird, spielt dies keine Rolle.
Phil294

Dies ist gut, wenn das alles ist, was Sie tun möchten, DELETEkann aber absolut brutal sein, wenn Sie zu viele Zeilen haben - da es die Protokolle trifft, während TRUNCATEnur die Daten herausgerissen werden. Kommt wirklich auf den Anwendungsfall an.
Jeff

1
Wenn ich die delete-Anweisung verwende, wird der Fehler 1175 gemeldet: Sie verwenden den sicheren Aktualisierungsmodus. Fügen Sie einfach SET SQL_SAFE_UPDATES = 0 hinzu. dann ist es gut
tyan

Bei Verwendung dieser Lösung wird eine error 1175: You are using safe update mode,...Änderungslöschklausel gemeldet, um DELETE FROM mydb.mytable where id != 0sie zu perfektionieren.
Shihe Zhang

17

du kannst tun

DELETE FROM `mytable` WHERE `id` > 0

1
Ich habe es versucht, aber der folgende Fehler ist aufgetreten: Fehlercode: 1142. Der Befehl DELETE wurde dem Benutzer 'root' @ 'localhost' für die Tabelle 'mytable'
verweigert

oder einfach LÖSCHEN VONmytable
Miloslav Milo Janoušek

Dies würde das automatische Inkrement nicht zurücksetzen.
vivek_23

13

Wie pro mysql Dokumentation , TRUNCATE kann nicht auf Tabellen mit Fremdschlüsselbeziehungen verwendet werden. Es gibt keine vollständige Alternative AFAIK.

Wenn Sie den Contraint fallen lassen, werden ON DELETE und ON UPDATE immer noch nicht aufgerufen. Die einzige Lösung, an die ich am Geldautomaten denken kann, ist:

  • Löschen Sie alle Zeilen, löschen Sie die Fremdschlüssel, schneiden Sie sie ab und erstellen Sie die Schlüssel neu
  • alle Zeilen löschen, auto_increment zurücksetzen (falls verwendet)

Es scheint, dass TRUNCATE in MySQL noch keine vollständige Funktion ist (es werden auch keine Trigger aufgerufen). Siehe Kommentar


7
Ein Hinweis zu Ihrem Punkt, dass MySQL TRUNCATEunvollständig ist - Abschneiden soll keine Trigger usw. aufrufen. Wenn dies der Fall wäre, wäre es genauso wie DELETE! Es ist zeilenunabhängig und kann daher keine zeilenbezogenen Vorgänge ausführen (z. B. Aufrufen von Triggern oder Untersuchen von Fremdschlüsseln). Dies funktioniert in Oracle und SQL Server auf die gleiche Weise .
Simon MᶜKenzie

8

Einfach, wenn Sie phpMyAdmin verwenden.

Deaktivieren Sie einfach die Enable foreign key checksOption unter der SQLRegisterkarte und führen Sie sie ausTRUNCATE <TABLE_NAME>

Geben Sie hier die Bildbeschreibung ein


8

Während diese Frage gestellt wurde, wusste ich nichts darüber, aber jetzt, wenn Sie phpMyAdmin verwenden, können Sie einfach die Datenbank öffnen und die Tabelle (n) auswählen, die Sie abschneiden möchten.

  • Unten gibt es ein Dropdown-Menü mit vielen Optionen. Öffnen Sie es und wählen Sie die EmptyOption unter der Überschrift Delete data or table.
  • Sie gelangen automatisch zur nächsten Seite, auf der eine Option im Kontrollkästchen aufgerufen wird Enable foreign key checks. Deaktivieren Sie es einfach und drücken Sie die YesTaste. Die ausgewählten Tabellen werden abgeschnitten.

Möglicherweise wird die in der Antwort von user447951 vorgeschlagene Abfrage intern ausgeführt, die Verwendung über die phpMyAdmin-Oberfläche ist jedoch sehr praktisch.


7

Getestet auf MYSQL-Datenbank

Lösung 1:

SET FOREIGN_KEY_CHECKS = 0;
TRUNCATE table1;

Lösung 2:

DELETE FROM table1;
ALTER TABLE table1 AUTO_INCREMENT = 1;
TRUNCATE table1;

Das funktioniert bei mir. Ich hoffe, das wird dir auch helfen. Vielen Dank, dass Sie diese Frage gestellt haben.


6

Die Antwort ist in der Tat die von zerkms , wie in Option 1 angegeben :

Option 1 : die keine Gefahr für die Datenintegrität birgt:

  1. Entfernen Sie Einschränkungen
  2. Führen Sie TRUNCATE aus
  3. Löschen Sie manuell die Zeilen, die jetzt auf nirgendwo verweisen
  4. Erstellen Sie Einschränkungen

Der schwierige Teil ist das Entfernen von Einschränkungen. Daher möchte ich Ihnen sagen, wie, falls jemand wissen muss, wie das geht:

  1. Führen Sie eine SHOW CREATE TABLE <Table Name>Abfrage aus, um zu sehen, wie Ihr AUSLÄNDISCHER SCHLÜSSEL heißt (roter Rahmen im Bild unten):

    Geben Sie hier die Bildbeschreibung ein

  2. Ausführen ALTER TABLE <Table Name> DROP FOREIGN KEY <Foreign Key Name>. Dadurch wird die Fremdschlüsseleinschränkung aufgehoben.

  3. Löschen Sie den zugehörigen Index (über die Tabellenstrukturseite), und fertig.

So erstellen Sie Fremdschlüssel neu:

ALTER TABLE <Table Name>
ADD FOREIGN KEY (<Field Name>) REFERENCES <Foreign Table Name>(<Field Name>);

3

Verwenden Sie einfach CASCADE

TRUNCATE "products" RESTART IDENTITY CASCADE;

Aber sei bereit für Kaskadenlöschungen)


3
Das OP hat MySQL markiert. Während dies in Postgres gültig ist, ist es in MySQL falsch.
Peter

1

Wenn sich das Datenbankmodul für Tabellen unterscheidet, wird dieser Fehler angezeigt. Ändern Sie sie daher in InnoDB

ALTER TABLE my_table ENGINE = InnoDB;

0

Das Abrufen des alten Fremdschlüsselprüfstatus und des SQL-Modus ist der beste Weg, um die Tabelle wie bei MySQL Workbench beim Synchronisieren des Modells mit der Datenbank abzuschneiden / zu löschen.

SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;`
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL,ALLOW_INVALID_DATES';

DROP TABLE TABLE_NAME;
TRUNCATE TABLE_NAME;

SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.