MySQL-Fehler 1452 - Eine untergeordnete Zeile kann nicht hinzugefügt oder aktualisiert werden: Eine Fremdschlüsseleinschränkung schlägt fehl

237

Ich habe ein seltsames Problem. Ich versuche, einer Tabelle einen Fremdschlüssel hinzuzufügen, der auf eine andere verweist, aber dies schlägt aus irgendeinem Grund fehl. Aufgrund meiner begrenzten Kenntnisse in MySQL kann möglicherweise nur vermutet werden, dass sich in einer anderen Tabelle ein Fremdschlüssel befindet, der auf den Schlüssel verweist, auf den ich verweisen möchte.

Ich habe eine SHOW CREATE TABLEAbfrage für beide Tabellen durchgeführt, sourcecodes_tagsist die Tabelle mit dem Fremdschlüssel, sourcecodesist die referenzierte Tabelle.

CREATE TABLE `sourcecodes` (
 `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
 `user_id` int(11) unsigned NOT NULL,
 `language_id` int(11) unsigned NOT NULL,
 `category_id` int(11) unsigned NOT NULL,
 `title` varchar(40) CHARACTER SET utf8 NOT NULL,
 `description` text CHARACTER SET utf8 NOT NULL,
 `views` int(11) unsigned NOT NULL,
 `downloads` int(11) unsigned NOT NULL,
 `time_posted` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
 PRIMARY KEY (`id`),
 KEY `user_id` (`user_id`),
 KEY `language_id` (`language_id`),
 KEY `category_id` (`category_id`),
 CONSTRAINT `sourcecodes_ibfk_3` FOREIGN KEY (`language_id`) REFERENCES `languages` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
 CONSTRAINT `sourcecodes_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
 CONSTRAINT `sourcecodes_ibfk_2` FOREIGN KEY (`category_id`) REFERENCES `categories` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1

CREATE TABLE `sourcecodes_tags` (
 `sourcecode_id` int(11) unsigned NOT NULL,
 `tag_id` int(11) unsigned NOT NULL,
 KEY `sourcecode_id` (`sourcecode_id`),
 KEY `tag_id` (`tag_id`),
 CONSTRAINT `sourcecodes_tags_ibfk_1` FOREIGN KEY (`tag_id`) REFERENCES `tags` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1

Dies ist der Code, der den Fehler generiert:

ALTER TABLE sourcecodes_tags ADD FOREIGN KEY (sourcecode_id) REFERENCES sourcecodes (id) ON DELETE CASCADE ON UPDATE CASCADE
Zim
quelle
2
Könnten Sie auch Ihren Befehl zum Einfügen / Aktualisieren veröffentlichen, der zu dem Fehler führt?
Zed
64
Sind Ihre Tabellen leer, wenn Sie diesen Fremdschlüssel hinzufügen?
Zed
12
Versuchen Sie, diese Abfrage auszuführen, um festzustellen, ob es eine Quellcode-ID gibt, die keine echte ID ist: SELECT Quellcode-ID FROM Quellcode-Tags WHERE Quellcode-ID NICHT IN (SELECT-ID VON Quellcodes AS tmp);
Zed
11
Danke Zed, das war das Problem, dass eine der Tabellen Daten enthielt. Wenn ich jetzt darüber nachdenke, ist es sinnvoll, dass es fehlgeschlagen ist, weil es Dinge gab, die auf nicht existierende Elemente verweisen, aber das hätte ich nie gedacht. Vielen Dank!
Zim
2
Warum schlägt es fehl, wenn die Tabelle leer ist?
Theblackpearl

Antworten:

226

Sehr wahrscheinlich sourcecodes_tagsenthält Ihre Tabelle sourcecode_idWerte, die in Ihrer sourcecodesTabelle nicht mehr vorhanden sind . Sie müssen diese zuerst loswerden.

Hier ist eine Abfrage, die diese IDs finden kann:

SELECT DISTINCT sourcecode_id FROM 
   sourcecodes_tags tags LEFT JOIN sourcecodes sc ON tags.sourcecode_id=sc.id 
WHERE sc.id IS NULL;
nr
quelle
UPDATE sourcecodes_tags SET sourcecode_id = NULL WHERE sourcecode_id NOT IN (SELECT id FROM sourcecodes)sollte helfen, diese IDs loszuwerden. Wenn dies nullnicht zulässig ist sourcecode_id, entfernen Sie diese Zeilen oder fügen Sie die fehlenden Werte zur sourcecodesTabelle hinzu.
NaXa
Ich habe das Gleiche gedacht, aber für mich SELECT Tchild.id FROM Tchild INNER JOIN Tmain ON Tmain.id = Tchild.fk_id WHERE Tmain.id IS NULLgibt es nichts zurück, also liegt das Problem woanders !?
Meloman
Ahh das war das Problem für mich. Ich habe versucht zu rennen UPDATE `homestead`.`automations` SET `deleted_at`=NULL WHERE deleted_at IS NOT NULL;, was überhaupt keinen Fremdschlüssel beinhaltete, also war ich verwirrt. Die Tatsache, dass in meiner Kontakttabelle einige Datensätze fehlten, auf die in der Automatisierungstabelle verwiesen wurde, führte dazu, dass dieser "Fehlercode: 1452" ausgelöst wurde. Eine untergeordnete Zeile kann nicht hinzugefügt oder aktualisiert werden: Eine Fremdschlüsseleinschränkung schlägt fehl.
Ryan
99

Ich hatte das gleiche Problem mit meiner MySQL-Datenbank, aber schließlich bekam ich eine Lösung, die für mich funktionierte.
Da in meiner Tabelle aus MySQL-Sicht alles in Ordnung war (beide Tabellen sollten die InnoDB-Engine verwenden und der Datentyp jeder Spalte sollte vom gleichen Typ sein, der an der Fremdschlüsseleinschränkung teilnimmt).
Das einzige, was ich getan habe, war, die Fremdschlüsselprüfung zu deaktivieren und sie später nach dem Ausführen der Fremdschlüsseloperation zu aktivieren.
Schritte, die ich unternommen habe:

SET foreign_key_checks = 0;
alter table tblUsedDestination add constraint f_operatorId foreign key(iOperatorId) references tblOperators (iOperatorId); Query
OK, 8 rows affected (0.23 sec) Records: 8  Duplicates: 0  Warnings: 0
SET foreign_key_checks = 1;
Prakash
quelle
49
Foreign_key_checks gibt es aus einem Grund. Wenn Sie den Fremdschlüssel nicht hinzufügen können, weil er gegen die Einschränkung verstößt, sollten Sie zuerst die Daten korrigieren. Wenn Sie Schecks deaktivieren und dann den Schlüssel hinzufügen, befinden Sie sich in einem inkonsistenten Zustand. Fremdschlüsselprüfungen verursachen zusätzlichen Aufwand. Wenn Sie sie nicht verwenden möchten, verwenden Sie stattdessen myisam.
cs_alumnus
5
@AbuSadatMohammedYasin nein sollte es nicht: Die Frage stellte "was ist los" und diese Antwort versucht einfach nicht, es zu erklären. Wie cs_alumnus erwähnt, gibt es ein größeres Problem: alle neuen Werte , die einen anderen Wert in der anderen Tabelle referenzieren (als sollten Fremdschlüssel sollte tun) zu nichts hinweisen, einen inkonsistenten Zustand zu schaffen. Mit der kurzen und effektiven Erklärung von Cayetano können Sie herausfinden, welche Werte Sie aktualisieren sollten, bevor Sie die Einschränkung erstellen, damit Sie nicht von Abfragen überrascht werden, die vorhandene Werte zurückgeben sollten!
Armfoot
55

Verwenden Sie NOT INzu finden , wo Einschränkungen werden beschränke :

SELECT column FROM table WHERE column NOT IN 
(SELECT intended_foreign_key FROM another_table)

also genauer:

SELECT sourcecode_id FROM sourcecodes_tags WHERE sourcecode_id NOT IN 
(SELECT id FROM sourcecodes)

BEARBEITEN: INund NOT INOperatoren sind bekanntermaßen viel schneller als die JOINOperatoren sowie viel einfacher zu konstruieren und zu wiederholen.

Ryan Ward
quelle
1
Wenn ich das richtig verstehe, können wir einer Tabelle, die bereits Daten enthält, einen Fremdschlüssel hinzufügen, aber nur, wenn für jede Zeile in der übergeordneten Tabelle eine untergeordnete Zeile vorhanden ist. Wenn für jede Zeile in der übergeordneten Tabelle keine untergeordneten Zeilen vorhanden sind (was Ihre Abfrage feststellt), schlägt das Fremdschlüsselskript fehl.
Vincent
@ Vincent Wenn mit übergeordneter Tabelle gemeint ist, dass auf die Tabelle verwiesen wird, dann ja! Daher erhalten Sie mit Cayetano's select alle Zeilen, die Sie aktualisieren / aus Ihrer "untergeordneten" Tabelle entfernen müssen, bevor Sie die neue Einschränkung (FK) hinzufügen. Sobald alle auf Werte in der "another_table" zeigen, können Sie loslegen!
Armfoot
23

Schneiden Sie die Tabellen ab und fügen Sie dann die FK-Einschränkung hinzu .

Ich weiß, dass diese Lösung etwas umständlich ist, aber sie funktioniert zu 100%. Aber ich stimme zu, dass dies keine ideale Lösung ist, um Probleme zu lösen, aber ich hoffe, es hilft.

Shankar Damodaran
quelle
4
Sie müssen nicht alles abschneiden. "UPDATE sourcecodes_tags SET sourcecode_id = NULL WHERE sourcecode_id NOT IN (SELECT id FROM sourcecodes)" sollte ausreichen. Oder wenn null in "sourcecode_id" nicht zulässig ist, entfernen Sie diese Zeilen oder fügen Sie diese fehlenden Werte zur Tabelle "sourcecodes" hinzu.
Torben
1
Wenn Daten die PK für die automatische Inkrementierung erhöhen, werden Sie manchmal zum Abschneiden gezwungen.
François Breton
2
@ShankarDamodaran nicht sicher, warum das Abschneiden der Tabelle funktioniert, aber diese Lösung hat bei mir gut funktioniert. Ich konnte meine Beziehungen zum Laufen bringen ... DANKE!
MizAkita
@MizAkita funktioniert, weil es die Zeilen löscht, die keinen entsprechenden Wert in der anderen Tabelle haben, wodurch die neue Einschränkung erstellt werden kann. Wenn Sie nur diese Zeilen finden und sie aktualisieren oder löschen (wie Cayetanos Vorschlag ), müssen Sie die anderen Zeilen nicht löschen ...
Armfoot
@Armfoot - Ich hatte dieses Problem beim Hinzufügen der ersten Zeile zur Tabelle mit dem Fremdschlüssel. Ich hatte also keine Zeilen zu suchen.
Krewetka
16

Für mich war dieses Problem etwas anders und super einfach zu überprüfen und zu lösen.

Sie müssen sicherstellen, dass BEIDE Ihrer Tabellen InnoDB sind. Wenn eine der Tabellen, nämlich die Referenztabelle, ein MyISAM ist, schlägt die Einschränkung fehl.

    SHOW TABLE STATUS WHERE Name =  't1';

    ALTER TABLE t1 ENGINE=InnoDB;
zmonteca
quelle
14

Dies geschieht auch, wenn ein Fremdschlüssel für parent.id auf child.column gesetzt wird, wenn die child.column bereits den Wert 0 hat und kein parent.id-Wert 0 ist

Sie müssen sicherstellen, dass jede child.column NULL ist oder einen Wert hat, der in parent.id vorhanden ist

Und jetzt, wo ich die Aussage gelesen habe, die nos geschrieben hat, bestätigt er dies.

fyrye
quelle
14

Ich hatte heute das gleiche Problem. Ich habe vier Dinge getestet, von denen einige bereits hier erwähnt wurden:

  1. Gibt es in Ihrer untergeordneten Spalte Werte, die in der übergeordneten Spalte nicht vorhanden sind (außer NULL, wenn die untergeordnete Spalte nullwertfähig ist)?

  2. Haben untergeordnete und übergeordnete Spalten denselben Datentyp?

  3. Gibt es einen Index für die übergeordnete Spalte, auf die Sie verweisen? MySQL scheint dies aus Leistungsgründen zu erfordern ( http://dev.mysql.com/doc/refman/5.5/en/create-table-foreign-keys.html ).

  4. Und dieser hat es für mich gelöst: Haben beide Tabellen eine identische Sortierung?

Ich hatte eine Tabelle in UTF-8 und die andere in ISO-Etwas. Das hat nicht funktioniert. Nach dem Ändern der ISO-Tabelle in UTF-8-Kollatierung konnten die Einschränkungen problemlos hinzugefügt werden. In meinem Fall hat phpMyAdmin in der Dropdown-Liste zum Erstellen der Fremdschlüsseleinschränkung nicht einmal die untergeordnete Tabelle in Isokodierung angezeigt.

Michael Helwig
quelle
7

Es scheint, dass es einen ungültigen Wert für die Spaltenzeile 0 gibt, der kein gültiger Fremdschlüssel ist, sodass MySQL keine Fremdschlüsseleinschränkung dafür festlegen kann.

Sie können die folgenden Schritte ausführen:

  1. Löschen Sie die Spalte, für die Sie versucht haben, die FK-Einschränkung festzulegen.

  2. Fügen Sie es erneut hinzu und setzen Sie den Standardwert auf NULL.

  3. Versuchen Sie erneut, eine Fremdschlüsseleinschränkung festzulegen.

Milad Rahimi
quelle
5

Ich hatte das gleiche Problem, ich überprüfte die Zeilen meiner Tabellen und stellte fest, dass es eine gewisse Inkompatibilität mit dem Wert von Feldern gab, für die ich einen Fremdschlüssel definieren wollte. Ich habe diesen Wert korrigiert, es erneut versucht und das Problem wurde gelöst.

Mostafa -T
quelle
4

Am Ende lösche ich alle Daten in meiner Tabelle und führe alter erneut aus. Es klappt. Nicht die brillante, aber es spart viel Zeit, insbesondere befindet sich Ihre Anwendung noch in der Entwicklungsphase ohne Kundendaten.

VHanded
quelle
4

Versuche dies

SET foreign_key_checks = 0;

ALTER TABLE sourcecodes_tags ADD FOREIGN KEY (sourcecode_id) REFERENCES sourcecodes (id) ON DELETE CASCADE ON UPDATE CASCADE

SET foreign_key_checks = 1;
Carlo Guevarra
quelle
2

Ich hatte genau das gleiche Problem ungefähr drei verschiedene Male. In jedem Fall lag es daran, dass einer (oder mehrere) meiner Datensätze nicht dem neuen Fremdschlüssel entsprachen. Möglicherweise möchten Sie Ihre vorhandenen Datensätze aktualisieren, um den Syntaxbeschränkungen des Fremdschlüssels zu folgen, bevor Sie versuchen, den Schlüssel selbst hinzuzufügen. Das folgende Beispiel sollte im Allgemeinen die Problemdatensätze isolieren:

SELECT * FROM (tablename)
    WHERE (candidate key) <> (proposed foreign key value) 
        AND (candidate key) <> (next proposed foreign key value)

Wiederholen Sie AND (candidate key) <> (next proposed foreign key value)innerhalb Ihrer Abfrage für jeden Wert im Fremdschlüssel.

Wenn Sie eine Menge Datensätze haben, kann dies schwierig sein, aber wenn Ihr Tisch relativ klein ist, sollte es nicht zu lange dauern. Ich bin in der SQL-Syntax nicht besonders beeindruckend, aber das hat das Problem für mich immer isoliert.

Mopsyd
quelle
2

Leeren Sie beide Daten Ihrer Tabellen und führen Sie den Befehl aus. Es wird klappen.

Vijayrana
quelle
VHanded gab die gleiche Antwort vor 3 Jahren. Hoffen wir, dass es keine wichtigen Daten in den Tabellen gab ...
xlecoustillier
1

Ich habe diese Lösungen vorbereitet und dieses Beispiel kann helfen.

Meine Datenbank enthält zwei Tabellen (E-Mail und Kreditkarte) mit Primärschlüsseln für ihre IDs. Eine andere Tabelle (Client) bezeichnet diese Tabellen-IDs als Fremdschlüssel. Ich habe einen Grund, die E-Mail neben den Kundendaten zu haben.

Zuerst füge ich die Zeilendaten für die referenzierten Tabellen (E-Mail, Kreditkarte) ein, dann erhalte ich die ID für jede Tabelle. Diese IDs werden in der dritten Tabelle (Client) benötigt.

Wenn Sie nicht zuerst die Zeilen in die Tabellen einfügen, auf die verwiesen wird, kann MySQL die Entsprechungen nicht herstellen, wenn Sie eine neue Zeile in die dritte Tabelle einfügen, die auf die Fremdschlüssel verweist.

Wenn Sie zuerst die referenzierten Zeilen für die referenzierten Tabellen einfügen, dann die Zeile, die auf Fremdschlüssel verweist, tritt kein Fehler auf.

Hoffe das hilft.

SubstanceMX
quelle
mysql> in E-Mail (E-Mail) Werte einfügen ('[email protected]'); mysql> in ndtc-Werte (ndtc, Jahr, Monat) einfügen ('1111222233334444', '2000', '01'); mysql> in cliente (nombres, apellidos, telefono, idNDTC, idEmail) Werte einfügen ('myname', 'myapp', '5555555555', 1,1);
SubstanceMX
1

Stellen Sie sicher, dass sich der Wert in der anderen Tabelle befindet. Andernfalls wird dieser Fehler in der zugewiesenen entsprechenden Spalte angezeigt.

Wenn die Spalte einer Zeilen-ID einer anderen Tabelle zugewiesen ist, stellen Sie sicher, dass sich eine Zeile in der Tabelle befindet. Andernfalls wird dieser Fehler angezeigt.

Kingsley Mitchell
quelle
1

Sie können dieses Beispiel ausprobieren

 START TRANSACTION;
 SET foreign_key_checks = 0;
 ALTER TABLE `job_definers` ADD CONSTRAINT `job_cities_foreign` FOREIGN KEY 
 (`job_cities`) REFERENCES `drop_down_lists`(`id`) ON DELETE CASCADE ON UPDATE CASCADE;
 SET foreign_key_checks = 1;
 COMMIT;

Hinweis: Wenn Sie phpmyadmin verwenden, deaktivieren Sie einfach die Option Fremdschlüsselprüfungen aktivieren

als Beispiel Geben Sie hier die Bildbeschreibung ein

hoffe, diese Lösung behebt dein Problem :)

Fouad Mekkey
quelle
1

Sie müssen nur eine Frage beantworten:

Speichert Ihre Tabelle bereits Daten? (Insbesondere die Tabelle enthielt Fremdschlüssel.)

Wenn die Antwort Ja lautet, müssen Sie nur alle Datensätze löschen. Anschließend können Sie Ihrer Tabelle einen beliebigen Fremdschlüssel hinzufügen.

Anweisung löschen: Von der untergeordneten Tabelle (einschließlich der Fremdschlüsseltabelle) zur übergeordneten Tabelle.

Der Grund, warum Sie nach der Dateneingabe keinen Fremdschlüssel hinzufügen können, liegt in der Tabelleninkonsistenz. Wie gehen Sie mit einem neuen Fremdschlüssel in der früheren Tabelle um, die mit Daten gefüllt ist?

Wenn die Antwort Nein lautet, befolgen Sie andere Anweisungen.

niemand
quelle
0
UPDATE sourcecodes_tags
SET sourcecode_id = NULL
WHERE sourcecode_id NOT IN (
  SELECT id FROM sourcecodes);

sollte helfen, diese IDs loszuwerden. Wenn dies nullnicht zulässig ist sourcecode_id, entfernen Sie diese Zeilen oder fügen Sie die fehlenden Werte zur sourcecodesTabelle hinzu.

naXa
quelle
0

Ich hatte das gleiche Problem und fand eine Lösung, Platzierung NULL anstatt NOT NULLauf einer Fremdschlüsselspalte zu platzieren. Hier ist eine Abfrage:

ALTER TABLE `db`.`table1`
ADD COLUMN `col_table2_fk` INT UNSIGNED NULL,
ADD INDEX `col_table2_fk_idx` (`col_table2_fk` ASC),
ADD CONSTRAINT `col_table2_fk1`
FOREIGN KEY (`col_table2_fk`)
REFERENCES `db`.`table2` (`table2_id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION;

MySQL hat diese Abfrage ausgeführt!

akelec
quelle
0

In meinem Fall habe ich eine neue Tabelle mit derselben Struktur erstellt, die Beziehungen zu den anderen Tabellen erstellt, dann die Daten in der CSV aus der alten Tabelle extrahiert, die das Problem aufweist, und dann die CSV in die neue Tabelle importiert und die Fremdschlüsselprüfung deaktiviert und deaktivierte Importunterbrechung, alle meine Daten werden in die neue Tabelle eingefügt, die kein Problem erfolgreich hat, und dann die alte Tabelle gelöscht.

Es hat bei mir funktioniert.

Shamal Sabah
quelle