Eine übergeordnete Zeile kann nicht gelöscht oder aktualisiert werden: Eine Fremdschlüsseleinschränkung schlägt fehl

170

Wenn Sie:

DELETE FROM `jobs` WHERE `job_id` =1 LIMIT 1 

Es Fehler:

#1451 - Cannot delete or update a parent row: a foreign key constraint fails 
(paymesomething.advertisers, CONSTRAINT advertisers_ibfk_1 FOREIGN KEY 
(advertiser_id) REFERENCES jobs (advertiser_id))

Hier sind meine Tabellen:

CREATE TABLE IF NOT EXISTS `advertisers` (
  `advertiser_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `password` char(32) NOT NULL,
  `email` varchar(128) NOT NULL,
  `address` varchar(255) NOT NULL,
  `phone` varchar(255) NOT NULL,
  `fax` varchar(255) NOT NULL,
  `session_token` char(30) NOT NULL,
  PRIMARY KEY (`advertiser_id`),
  UNIQUE KEY `email` (`email`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;


INSERT INTO `advertisers` (`advertiser_id`, `name`, `password`, `email`, `address`, `phone`, `fax`, `session_token`) VALUES
(1, 'TEST COMPANY', '', '', '', '', '', '');

CREATE TABLE IF NOT EXISTS `jobs` (
  `job_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `advertiser_id` int(11) unsigned NOT NULL,
  `name` varchar(255) NOT NULL,
  `shortdesc` varchar(255) NOT NULL,
  `longdesc` text NOT NULL,
  `address` varchar(255) NOT NULL,
  `time_added` int(11) NOT NULL,
  `active` tinyint(1) NOT NULL,
  `moderated` tinyint(1) NOT NULL,
  PRIMARY KEY (`job_id`),
  KEY `advertiser_id` (`advertiser_id`,`active`,`moderated`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;


INSERT INTO `jobs` (`job_id`, `advertiser_id`, `name`, `shortdesc`, `longdesc`, `address`, `active`, `moderated`) VALUES
(1, 1, 'TEST', 'TESTTEST', 'TESTTESTES', '', 0, 0);

ALTER TABLE `advertisers`
  ADD CONSTRAINT `advertisers_ibfk_1` FOREIGN KEY (`advertiser_id`) REFERENCES `jobs` (`advertiser_id`);
Steven
quelle

Antworten:

108

Sie müssen die Zeile aus der Tabelle der Werbetreibenden löschen, bevor Sie die Zeile in der Jobtabelle löschen können, auf die sie verweist. Dies:

ALTER TABLE `advertisers`
  ADD CONSTRAINT `advertisers_ibfk_1` FOREIGN KEY (`advertiser_id`) 
      REFERENCES `jobs` (`advertiser_id`);

... ist eigentlich das Gegenteil von dem, was es sein sollte. Dies bedeutet, dass Sie vor den Werbetreibenden einen Datensatz in der Jobtabelle haben müssen. Sie müssen also Folgendes verwenden:

ALTER TABLE `jobs`
  ADD CONSTRAINT `advertisers_ibfk_1` FOREIGN KEY (`advertiser_id`) 
      REFERENCES `advertisers` (`advertiser_id`);

Sobald Sie die Fremdschlüsselbeziehung korrigiert haben, funktioniert Ihre Löschanweisung.

OMG Ponys
quelle
3
In der ersten Zeile: Glauben Sie nicht, dass es "dass es referenziert" statt "das referenziert" sein sollte? Oder habe ich falsch verstanden, wie die Referenzterminologie funktionieren soll?
Abraham Philip
6
@AbrahamPhilip Ich dachte das gleiche. Werbetreibende verweisen auf Jobs.
Keyser
270

Der einfache Weg wäre, die Fremdschlüsselprüfung zu deaktivieren. Nehmen Sie die Änderungen vor und aktivieren Sie die Fremdschlüsselprüfung erneut.

SET FOREIGN_KEY_CHECKS=0; -- to disable them
SET FOREIGN_KEY_CHECKS=1; -- to re-enable them
Alino Manzi
quelle
171
Dies ist keine Lösung für das Problem, sondern eine schmutzige Umgehung, die möglicherweise nicht erwünscht ist.
Madfriend
20
In meinem Fall: Ich habe gerade eine große SQL-Datei ausgeführt und eine der endgültigen Anweisungen ist fehlgeschlagen. Daher möchte ich einfach alle Tabellen löschen, den Syntaxfehler beheben und erneut ausführen, um genau das zu erreichen, wonach ich gesucht habe.
ekerner
1
Wenn Sie dies tun würden, warum nicht einfach alle Einschränkungen entfernen?
Sablefoste
1
Es ist nützlich, wenn Sie etwas tun wie:REPLACE INTO tab_with_constraint ...
Maciek Łoziński
5
Der einzige Grund, diese Antwort zu verbessern, ist, wenn Sie nur möchten, dass Ihr Code Sie nicht mehr anschreit und tiefer in Spaghetti eindringt, ohne den Code zu verstehen, den Sie schreiben. Der Grund für Fremdschlüssel besteht in der Durchsetzung der referenziellen Integrität. Wenn Sie sie deaktivieren müssen, um Ihren Code herunterzufahren, möchten Sie wahrscheinlich Ihre Fremdschlüssel überdenken, anstatt sie zu deaktivieren.
Cytinus
38

Unter Ihrem aktuellen (möglicherweise fehlerhaften) Design müssen Sie die Zeile aus der Tabelle der Werbetreibenden löschen, bevor Sie die Zeile in der Jobtabelle löschen können, auf die sie verweist.

Alternativ können Sie Ihren Fremdschlüssel so einrichten, dass beim Löschen in der übergeordneten Tabelle Zeilen in untergeordneten Tabellen automatisch gelöscht werden. Dies wird als kaskadierendes Löschen bezeichnet. Es sieht ungefähr so ​​aus:

ALTER TABLE `advertisers`
ADD CONSTRAINT `advertisers_ibfk_1`
FOREIGN KEY (`advertiser_id`) REFERENCES `jobs` (`advertiser_id`)
ON DELETE CASCADE;

Wie andere bereits betont haben, sollte Ihr Fremdschlüssel jedoch umgekehrt sein, da die Tabelle der Werbetreibenden tatsächlich den Primärschlüssel und die Jobtabelle den Fremdschlüssel enthält. Ich würde es so umschreiben:

ALTER TABLE `jobs`
ADD FOREIGN KEY (`advertiser_id`) REFERENCES `advertisers` (`advertiser_id`);

Und das kaskadierende Löschen ist nicht erforderlich.

Asaph
quelle
18

Wenn Sie eine Tabelle löschen möchten, sollten Sie die folgende Abfrage in einem einzigen Schritt ausführen

SET FOREIGN_KEY_CHECKS = 0; DROP TABLE Tabellenname;

Abin John
quelle
13

Ich habe die von @Alino Manzi erwähnte Lösung ausprobiert, aber sie funktionierte bei mir in den WordPress-bezogenen Tabellen mit wpdb nicht.

dann habe ich den Code wie folgt geändert und es hat funktioniert

SET FOREIGN_KEY_CHECKS=OFF; //disabling foreign key

//run the queries which are giving foreign key errors

SET FOREIGN_KEY_CHECKS=ON; // enabling foreign key
Moh .S
quelle
6

Ich denke, dass Ihr Fremdschlüssel rückwärts ist. Versuchen:

ALTER TABLE 'jobs'
ADD CONSTRAINT `advertisers_ibfk_1` FOREIGN KEY (`advertiser_id`) REFERENCES `advertisers` (`advertiser_id`)
Tom H.
quelle
5

Wenn es mehr als einen Job mit derselben Advertiser_ID gibt, sollte Ihr Fremdschlüssel wie folgt lauten:

ALTER TABLE `jobs`
ADD CONSTRAINT `advertisers_ibfk_1` 
FOREIGN KEY (`advertiser_id`) 
REFERENCES `advertisers` (`advertiser_id`);

Andernfalls (wenn es in Ihrem Fall umgekehrt ist), wenn Sie möchten, dass die Zeilen im Werbetreibenden automatisch gelöscht werden, wenn die Zeile im Job gelöscht wird, fügen Sie die Option "CASCADE LÖSCHEN" am Ende Ihres Fremdschlüssels hinzu:

ALTER TABLE `advertisers`
ADD CONSTRAINT `advertisers_ibfk_1` 
FOREIGN KEY (`advertiser_id`) 
REFERENCES `jobs` (`advertiser_id`)
ON DELETE CASCADE;

Überprüfen Sie die Fremdschlüsseleinschränkungen

SO Benutzer
quelle
3

Sie müssen es nach Reihenfolge löschen. Die Tabellen enthalten Abhängigkeiten

Ran Adler
quelle
2

Wenn Sie eine Datenbank erstellen oder Tabellen erstellen

Sie sollten diese Zeile am oberen Skript hinzufügen, um eine Datenbank oder Tabelle zu erstellen

SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=1;

Jetzt möchten Sie Datensätze aus der Tabelle löschen? dann schreibst du als

SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=1;
DELETE FROM `jobs` WHERE `job_id` =1 LIMIT 1

Viel Glück!

Quy Le
quelle
2

Wie wäre es mit dieser Alternative, die ich verwendet habe: Lassen Sie den Fremdschlüssel NULL sein und wählen Sie dann ON DELETE SET NULL .

Persönlich bevorzuge ich die Verwendung von " ON UPDATE CASCADE " sowie " ON DELETE SET NULL ", um unnötige Komplikationen zu vermeiden, aber bei Ihrer Einrichtung möchten Sie möglicherweise einen anderen Ansatz. Das NULL-Senden von Fremdschlüsselwerten kann letztere zu Komplikationen führen, da Sie nicht genau wissen, was dort passiert ist. Diese Änderung sollte also in engem Zusammenhang mit der Funktionsweise Ihres Anwendungscodes stehen.

Hoffe das hilft.

Marius Cucuruz
quelle
2

Ich hatte dieses Problem in Laravel Migration zu
der Reihenfolge der Drop - Tabellen in nach unten () Methode does matter

Schema::dropIfExists('groups');
Schema::dropIfExists('contact');

funktioniert möglicherweise nicht, aber wenn Sie die Reihenfolge ändern, funktioniert es.

Schema::dropIfExists('contact');
Schema::dropIfExists('groups');
Amin
quelle
1

Wenn Sie den Client so schnell wie möglich unterstützen müssen und keinen Zugriff darauf haben

FOREIGN_KEY_CHECKS

damit die Datenintegrität deaktiviert werden kann:

1) Fremdschlüssel löschen

ALTER TABLE `advertisers` 
DROP FOREIGN KEY `advertisers_ibfk_1`;

2) Aktivieren Sie Ihren Löschvorgang über SQL oder API

3) Fügen Sie den Fremdschlüssel wieder zum Schema hinzu

ALTER TABLE `advertisers`
  ADD CONSTRAINT `advertisers_ibfk_1` FOREIGN KEY (`advertiser_id`) REFERENCES `jobs` (`advertiser_id`);

Es handelt sich jedoch um eine Hotfix-Lösung, die auf eigenes Risiko erfolgt, da der Hauptfehler eines solchen Ansatzes darin besteht, dass die Datenintegrität anschließend manuell beibehalten werden muss.

Oleksii Kyslytsyn
quelle
0

Sie können einen Auslöser erstellen, um die referenzierten Zeilen vor dem Löschen des Jobs zu löschen.

    DELIMITER $$
    CREATE TRIGGER before_jobs_delete 
        BEFORE DELETE ON jobs
        FOR EACH ROW 
    BEGIN
        delete from advertisers where advertiser_id=OLD.advertiser_id;
    END$$
    DELIMITER ;
Patch92
quelle
0

Das Hauptproblem bei diesem Fehler Error Code: 1451. Cannot delete or update a parent row: a foreign key constraint failsbesteht darin, dass Sie nicht wissen, welche Tabelle den FK-Fehler enthält , sodass es schwierig ist, den Konflikt zu lösen.

Wenn Sie MySQL oder ähnliches verwenden, habe ich festgestellt, dass Sie ein ER-Diagramm für Ihre Datenbank erstellen und dann alle Konflikte, die den Fehler auslösen, überprüfen und sicher entfernen können.

  1. Verwenden Sie die MySQL-Workbench
  2. Klicken Sie auf Datenbank -> Reverse Engineering
  3. Wählen Sie eine richtige connection
  4. Denken Sie bis zum Ende daran, database& auszuwählen tables, die überprüft werden müssen
  5. Jetzt haben Sie das ER-Diagramm, Sie können sehen, welche Tabelle FK-Konflikt hat
Ng Sek Long
quelle
0

Grundsätzlich liegt der Grund für diese Art von Fehler darin, dass Sie möglicherweise versuchen, ein Tupple zu löschen, das einen Primärschlüssel (Stammtabelle) enthält und dessen Primärschlüssel in der untergeordneten Tabelle als Fremdschlüssel verwendet wird. In diesem Szenario müssen Sie zum Löschen übergeordneter Tabellendaten untergeordnete Tabellendaten entfernen (in denen der Fremdschlüssel verwendet wird). Vielen Dank

kishan99
quelle
0

Dies ist mir auch passiert und aufgrund einer Abhängigkeit und Referenz von anderen Tabellen konnte ich den Eintrag nicht entfernen. Ich habe der Tabelle eine Löschspalte (vom Typ Boolean) hinzugefügt. Der Wert in diesem Feld zeigte an, ob das Element zum Löschen markiert ist oder nicht. Wenn zum Löschen markiert, nicht abrufen / verwenden; Andernfalls verwenden Sie es.

Tariq Kamal
quelle
-1

Vielleicht sollten Sie ON DELETE CASCADE ausprobieren


quelle
34
Das blinde Hinzufügen eines kaskadierenden Löschvorgangs (der Daten zerstört), ohne das Problem zu verstehen, ist fast das Schlimmste, was man tun kann.
Tom H