Falsche Fremdschlüsseleinschränkung schlägt fehl

110

Ich erhalte diese Fehlermeldung:

FEHLER 1217 (23000) in Zeile 40: Eine übergeordnete Zeile kann nicht gelöscht oder aktualisiert werden: Eine Fremdschlüsseleinschränkung schlägt fehl

... wenn ich versuche einen Tisch fallen zu lassen:

DROP TABLE IF EXISTS `area`;

... so definiert:

CREATE TABLE `area` (
  `area_id` char(3) COLLATE utf8_spanish_ci NOT NULL,
  `nombre_area` varchar(30) COLLATE utf8_spanish_ci NOT NULL,
  `descripcion_area` varchar(100) COLLATE utf8_spanish_ci NOT NULL,
  PRIMARY KEY (`area_id`),
  UNIQUE KEY `nombre_area_UNIQUE` (`nombre_area`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_spanish_ci;

Das Lustige ist, dass ich bereits alle anderen Tabellen im Schema gelöscht habe, gegen die Fremdschlüssel vorhanden sind area. Tatsächlich ist die Datenbank bis auf die areaTabelle leer .

Wie kann es möglicherweise untergeordnete Zeilen haben, wenn sich kein anderes Objekt in der Datenbank befindet? Soweit ich weiß, erlaubt InnoDB keine Fremdschlüssel in anderen Schemas, oder?

(Ich kann sogar einen RENAME TABLE area TO something_elseBefehl ausführen : -?)

Álvaro González
quelle
Ist es möglich, dass die Tabelle Teil einer Referential-Integrity-Beziehung in einem anderen Schema ist?
Raj More
Ich habe einige andere Kopien der App, so dass es immer möglich ist. Die von mir verwendete Syntax lautet jedoch im Grunde genommen CONSTRAINT fk_servicio_area1 FOREIGN KEY (area_id) REFERENCES area (area_id), dh kein Schemaname in der Tabellenreferenz: -?
Álvaro González

Antworten:

101

Zwei Möglichkeiten:

  1. In einem anderen Schema ("Datenbank" in der MySQL-Terminologie) befindet sich eine Tabelle mit einer FK-Referenz
  2. Das interne Datenwörterbuch von innodb ist nicht mit dem MySQL-Wörterbuch synchron.

Sie können sehen, um welche Tabelle es sich handelt (eine davon jedenfalls), indem Sie einen "SHOW ENGINE INNODB STATUS" ausführen, nachdem das Löschen fehlgeschlagen ist.

Wenn sich herausstellt, dass dies der letztere Fall ist, würde ich den gesamten Server sichern und wiederherstellen, wenn Sie können.

MySQL 5.1 und höher gibt Ihnen den Namen der Tabelle mit dem FK in der Fehlermeldung.

MarkR
quelle
1
Ich kann das Problem nicht mehr reproduzieren. Das nicht synchronisierte Wörterbuch ist ein wahrscheinlicher Grund. Ich werde es Tag testen und sehen, welche SHOW ENGINE INNODB STATUSBerichte.
Álvaro González
3
Vielen Dank für diese Antwort! Ich hatte eine Viele-zu-Viele-Tabelle, die immer noch auf die Tabelle verweist, die wir nicht löschen konnten, also musste ich diese Tabelle zuerst löschen.
Christian Oudard
5
SHOW ENGINE INNODB STATUS listet den letzten Fremdschlüsselfehler unter "LATEST FOREIGN KEY ERROR" auf. Dies hat einen Zeitstempel.
Brame
Möglicherweise gibt es eine Tabelle mit einem Referenzschlüssel für die Betreff-Tabelle. es war in meinem Fall so.
RT
Viel Zeit gespart. Löschte die Datenbank unter "LATEST FOREIGN KEY ERROR"
Sand1512
121

Auf Anfrage, jetzt als Antwort ...

Bei Verwendung von MySQL Query Browser oder phpMyAdmin wird anscheinend für jede Abfrage eine neue Verbindung geöffnet ( bugs.mysql.com/bug.php?id=8280 ), sodass alle drop-Anweisungen in einer Abfrage geschrieben werden müssen, z.

SET FOREIGN_KEY_CHECKS=0; 
DROP TABLE my_first_table_to_drop; 
DROP TABLE my_second_table_to_drop; 
SET FOREIGN_KEY_CHECKS=1; 

Wo das SET FOREIGN_KEY_CHECKS=1als zusätzliche Sicherheitsmaßnahme dient ...

Karlis ritt
quelle
2
Für diejenigen, die einen Speicherauszug mit phpMyAdmin erstellen, gibt es eine Option "Fremdschlüsselprüfungen deaktivieren", die automatisch SET FOREIGN_KEY_CHECKS=0;zum Beginn des Speicherauszugs hinzugefügt wird .
Mike
Scheint, als hätte phpMyAdmin diese schöne Funktion implementiert, jetzt warte ich darauf, dass mysqlWorkbench dasselbe tut! :)
Karlis Rode
@CodeMed FYI, ich habe die Antwort von MarkR akzeptiert, weil sie eine sinnvolle Erklärung für das Problem enthält - obwohl ich zugeben muss, dass ich sie nicht überprüfen konnte, da ich in den folgenden 6 Jahren nicht einmal mit demselben Problem konfrontiert war, nicht einmal. Diese und frühere Antworten bieten eine Problemumgehung (ideal für dieses Gute), sprechen jedoch die Frage selbst nicht wirklich an, und da Sie nur eine Antwort akzeptieren können, musste ich mich entscheiden.
Álvaro González
1
Warnung: Dies ist keine Lösung, sondern nur die Problemumgehung für faule Männer. Nachdem Sie dies verwendet haben (wobei Datensätze in einigen anderen Tabellen auf die abgelegte Tabelle verweisen), werden Fremdschlüssel baumeln, die die Konsistenz (das C in ACID ) Ihrer Datenbank tödlich beeinträchtigen, und Ihre Anwendungen werden überall Ausnahmen auslösen . Du wurdest gewarnt.
bekce
Obwohl ich sicher bin, dass die Warnung von bekce verstanden und beachtet werden sollte, hat diese Lösung für mich funktioniert, in einer Situation, in der ich zuversichtlich war, dass ich auch alle Tabellen gelöscht habe, die auf die Tabellen mit den problematischen Einschränkungen für Fremdschlüssel verweisen.
user1147171
47

Deaktivieren Sie die Fremdschlüsselprüfung

SET FOREIGN_KEY_CHECKS=0
Flakron Bytyqi
quelle
62
Der richtige Befehl scheint zu sein SET FOREIGN_KEY_CHECKS=0und behebt die Fehlermeldung. Haben Sie eine Vorstellung davon, warum dies erforderlich ist? Werden Fremdschlüssel auch nach dem Wegfall der Tabellen zwischengespeichert?
Álvaro González
1
Um die Wahrheit zu sagen, ich habe keine Ahnung, warum ein solches Problem auftritt, aber stellen Sie sicher, dass Sie die Schlüsselüberprüfung jedes Mal deaktivieren, wenn Sie große Änderungen oder Aktualisierungen vornehmen. Es ist mir mehrmals passiert und hat mich tagelang ohne Schlaf gelassen.
Flakron Bytyqi
55
Stellen Sie sicher, dass SET FOREIGN_KEY_CHECKS=1;Sie fertig sind!
pedro_sland
5
Bei Verwendung von MySQL Query Browser oder phpMyAdmin wird anscheinend für jede Abfrage eine neue Verbindung geöffnet ( bugs.mysql.com/bug.php?id=8280 ), sodass alle drop-Anweisungen in einer Abfrage geschrieben werden müssen, z. SET FOREIGN_KEY_CHECKS=0; DROP TABLE my_first_table_to_drop; DROP TABLE my_second_table_to_drop; SET FOREIGN_KEY_CHECKS=1; Wobei das SET FOREIGN_KEY_CHECKS = 1 als zusätzliche Sicherheitsmaßnahme dient ...
Karlis Rode
1
@ KarlisRode, Bravo für den Kommentar zu phpMyAdmin. Wenn Sie das als Antwort setzen würden, würde ich es +1.
Sablefoste
28

von diesem Blog :

Sie können Fremdschlüsselprüfungen vorübergehend deaktivieren:

SET FOREIGN_KEY_CHECKS=0;

Stellen Sie einfach sicher, dass Sie sie wiederherstellen, wenn Sie fertig sind:

SET FOREIGN_KEY_CHECKS=1;
JackD
quelle
Schöne Antwort, als ich mich auf lokal entwickelte :)
Adelin
Es ist eine gültige Problemumgehung (ich kann bestätigen, dass sie funktioniert), aber der verknüpfte Blogeintrag spricht nicht wirklich über das Szenario in dieser Frage (eine Datenbank, die bis auf eine Tabelle bereits leer ist).
Álvaro González
6

hoffentlich seine Arbeit

SET Foreign_key_checks = 0; TROPFENTABELLE table name; SET Foreign_key_checks = 1;

M_ Fa
quelle
Ja, es funktioniert, wie schon mehrmals erwähnt ;-)
Álvaro González
1

Auf Schienen kann man Folgendes tun mit rails console:

connection = ActiveRecord::Base.connection
connection.execute("SET FOREIGN_KEY_CHECKS=0;")
yeyo
quelle
0

Möglicherweise haben Sie beim Arbeiten mit dieser Tabelle zuvor einen Fehler erhalten. Sie können die Tabelle umbenennen und erneut versuchen, sie zu entfernen.

ALTER TABLE `area` RENAME TO `area2`;
DROP TABLE IF EXISTS `area2`;
Vadim Pluzhinsky
quelle
0

Ich fand eine einfache Lösung, exportierte die Datenbank, bearbeitete sie, was Sie in einem Texteditor bearbeiten möchten, und importierte sie dann. Getan

Abdulrahman K.
quelle
4
Das ist eine interessante Lösung, die eigentlich eigentlich nicht passieren sollte. Stattdessen sollte alles, was geändert werden muss, über das DBMS erfolgen. Das Bearbeiten eines Datenbank-Dumps in einem Texteditor scheint ein reifer Weg für Probleme zu sein.
Brandon Anzaldi
1
Ich verstehe nicht wirklich, worauf du stehst. Wenn Sie die Datenbank sichern, den CREATE TABLECode entfernen und den Speicherauszug erneut laden, wird MySQL die Tabelle nicht entfernen. Und wenn Sie meinen, den Speicherauszug in einer neuen Datenbank wiederherzustellen ... Wenn Sie alle Tabellen wie mich löschen möchten, ist eine neu erstellte Datenbank bereits leer. Wenn Sie einige Tabellen behalten möchten, SET FOREIGN_KEY_CHECKS=0funktioniert die hier überall erwähnte Problemumgehung einwandfrei und ist einfacher. und Sie müssen den Speicherauszug wahrscheinlich sowieso nicht bearbeiten, da die neue Kopie Ihrer Daten möglicherweise kein nicht synchrones Datenwörterbuch enthält.
Álvaro González
-1

Eine übergeordnete Zeile kann nicht gelöscht oder aktualisiert werden: Eine Fremdschlüsseleinschränkung schlägt fehl ( table1. user_role, CONSTRAINT FK143BF46A8dsfsfds@#5A6BD60FOREIGN KEY ( user_id) REFERENCES user(.id ))

Was ich in zwei einfachen Schritten gemacht habe. Zuerst lösche ich die untergeordnete Zeile in der untergeordneten Tabelle wie

mysql> aus Tabelle2 löschen, wobei role_id = 2 && user_id = 20;

Abfrage OK, 1 Zeile betroffen (0,10 Sek.)

und zweiter Schritt als Löschen des übergeordneten Elements

aus Tabelle1 löschen, wobei id = 20;

Abfrage OK, 1 Zeile betroffen (0,12 Sek.)

Damit löse ich das Problem, was bedeutet, Kind löschen, dann Eltern löschen

Ich hoffe du hast es verstanden. :) :)

Aadil Masavir
quelle
Bitte lesen Sie die Frage noch einmal. Sie können eine nicht vorhandene Tabelle nicht entfernen.
Álvaro González
In diesem Szenario können wir die Fremdschlüsseleinschränkung entfernen und dann versuchen, die Tabelle zu löschen. Wir können einen Fremdschlüssel wie diesen löschen. ALTER TABLE <TABLE_NAME> DROP CONSTRAINT <FOREIGN_KEY_NAME>
Aadil Masavir