Błąd MySQL 1452 - Nie można dodać lub zaktualizować wiersza podrzędnego: ograniczenie klucza obcego kończy się niepowodzeniem

237

Mam trochę dziwny problem. Próbuję dodać klucz obcy do jednej tabeli, która odwołuje się do innej, ale z jakiegoś powodu nie działa. Przy mojej ograniczonej wiedzy o MySQL jedyną rzeczą, którą można podejrzewać, jest istnienie klucza obcego w innej tabeli odwołującej się do tej, o którą próbuję się powołać.

Zrobiłem SHOW CREATE TABLEzapytanie na obu tabelach, sourcecodes_tagsczy tabela z kluczem obcym sourcecodesjest tabelą , do której istnieje odniesienie.

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

To jest kod, który generuje błąd:

ALTER TABLE sourcecodes_tags ADD FOREIGN KEY (sourcecode_id) REFERENCES sourcecodes (id) ON DELETE CASCADE ON UPDATE CASCADE
Zim
źródło
2
czy możesz również opublikować polecenie wstawiania / aktualizacji, które powoduje błąd?
Zed,
64
czy twoje tabele są puste po dodaniu tego klucza obcego?
Zed,
12
spróbuj uruchomić to zapytanie, aby sprawdzić, czy istnieje identyfikator kodu źródłowego, który nie jest prawdziwym identyfikatorem: WYBIERZ identyfikator kodu źródłowego Z tagów kodu źródłowego GDZIE NIE ID kodu źródłowego (WYBIERZ identyfikator z kodów źródłowych AS tmp);
Zed,
11
Dzięki Zed, to był problem, że jedna z tabel zawierała dane. Myślenie o tym teraz ma sens, że zawiodło, ponieważ były rzeczy, które odwoływały się do nieistniejących przedmiotów, ale nigdy bym tego nie zgadł. Dzięki!
Zim,
2
Dlaczego zawodzi, jeśli tabela jest pusta?
theblackpearl

Odpowiedzi:

226

Całkiem prawdopodobne, że twoja sourcecodes_tagstabela zawiera sourcecode_idwartości, których już nie ma sourcecodes. Najpierw musisz się ich pozbyć.

Oto zapytanie, które może znaleźć te identyfikatory:

SELECT DISTINCT sourcecode_id FROM 
   sourcecodes_tags tags LEFT JOIN sourcecodes sc ON tags.sourcecode_id=sc.id 
WHERE sc.id IS NULL;
nr
źródło
UPDATE sourcecodes_tags SET sourcecode_id = NULL WHERE sourcecode_id NOT IN (SELECT id FROM sourcecodes)powinno pomóc pozbyć się tych identyfikatorów. Lub jeśli nullnie jest dozwolone sourcecode_id, usuń te wiersze lub dodaj brakujące wartości do sourcecodestabeli.
naXa
Myślałem tak samo, ale dla mnie SELECT Tchild.id FROM Tchild INNER JOIN Tmain ON Tmain.id = Tchild.fk_id WHERE Tmain.id IS NULLnic nie zwraca, więc problem jest gdzie indziej!
Meloman
Achh, to był dla mnie problem. Próbowałem uruchomić UPDATE `homestead`.`automations` SET `deleted_at`=NULL WHERE deleted_at IS NOT NULL;, który w ogóle nie wymagał klucza obcego, więc byłem zdezorientowany. Ale fakt, że w mojej tabeli kontaktów brakowało niektórych rekordów, do których odwoływała się tabela automatyzacji, spowodował wyświetlenie tego „Kod błędu: 1452. Nie można dodać lub zaktualizować wiersza podrzędnego: ograniczenie klucza obcego kończy się niepowodzeniem”.
Ryan
99

Miałem ten sam problem z bazą danych MySQL, ale w końcu dostałem rozwiązanie, które działało dla mnie.
Ponieważ w mojej tabeli wszystko było w porządku z punktu widzenia mysql (obie tabele powinny używać silnika InnoDB, a typ danych każdej kolumny powinien być tego samego typu, który bierze udział w ograniczeniu klucza obcego).
Jedyne, co zrobiłem, to wyłączenie sprawdzania klucza obcego, a później włączenie go po wykonaniu operacji na kluczu obcym.
Kroki, które podjąłem:

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
źródło
49
obce_kluczowe_klucze istnieją z jakiegoś powodu. Jeśli nie możesz dodać klucza obcego, ponieważ narusza to ograniczenie, najpierw popraw dane. Wyłączenie kontroli, a następnie dodanie klucza pozostawia cię w niespójnym stanie. Sprawdzanie klucza obcego dodaje koszty ogólne, jeśli nie chcesz ich używać, zamiast tego użyj myisam.
cs_alumnus
5
@AbuSadatMohammedYasin nie, nie powinno: pytanie brzmiało „co się dzieje”, a ta odpowiedź po prostu nie próbuje tego wyjaśnić. Jak wspomniano cs_alumnus, istnieje większy problem: wszystkie nowe wartości, które powinny odwoływać się do innej wartości w drugiej tabeli (jak powinien to zrobić klucz obcy ), mogą wskazywać na nic, tworząc niespójny stan. Krótkie i skuteczne wyjaśnienie Cayetano pozwala znaleźć wartości, które należy zaktualizować przed utworzeniem ograniczenia, aby nie dziwić zapytania, które powinny zwracać wartości, które powinny istnieć!
Armfoot
55

Użyj, NOT INaby dowiedzieć się, gdzie ograniczenia są ograniczone :

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

a dokładniej:

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

EDYCJA: INa NOT INoperatory są znacznie szybsze niż JOINoperatory, a także o wiele łatwiejsze do zbudowania i powtórzenia.

Ryan Ward
źródło
1
Więc jeśli dobrze to rozumiem, możemy dodać klucz obcy do tabeli, która już zawiera dane, ale tylko jeśli istnieje wiersz podrzędny dla każdego wiersza w tabeli nadrzędnej? Jeśli nie ma wierszy podrzędnych dla każdego wiersza w tabeli nadrzędnej (co odkrywa zapytanie), skrypt klucza obcego zawiedzie.
Vincent
@Vincent, jeśli przez tabelę nadrzędną rozumiesz tabelę, do której następuje odwołanie, to tak! Dlatego dzięki Cayetano's select otrzymujesz wszystkie wiersze, które musisz zaktualizować / usunąć ze swojej tabeli „podrzędnej” przed dodaniem nowego ograniczenia (FK). Gdy wszystkie wskażą wartości w „kolejnej tabeli”, możesz zacząć!
Armfoot
23

Obetnij tabele, a następnie spróbuj dodać ograniczenie FK .

Wiem, że to rozwiązanie jest trochę niezręczne, ale działa w 100%. Zgadzam się jednak, że nie jest to idealne rozwiązanie problemu, ale mam nadzieję, że to pomoże.

Shankar Damodaran
źródło
4
Nie trzeba obcinać wszystkiego. „AKTUALIZACJA sourcecodes_tags SET sourcecode_id = NULL GDZIE NIE SURCecode_id NOT IN (WYBIERZ identyfikator z sourcecodes)” powinno wystarczyć. Lub jeśli null nie jest dozwolony w „sourcecode_id”, usuń te wiersze lub dodaj brakujące wartości do tabeli „sourcecodes”.
Torben,
1
Czasami, jeśli dane zwiększają wartość autoinkrementacji PK, wymusza to obcięcie.
François Breton
2
@ShankarDamodaran nie jestem pewien, dlaczego obcinanie stołu działa, ale to rozwiązanie działało dobrze dla mnie. Udało mi się sprawić, by moje relacje działały ... DZIĘKI!
MizAkita
@MizAkita działa, ponieważ usuwa wiersze, które nie mają odpowiadającej wartości w drugiej tabeli, umożliwiając utworzenie nowego ograniczenia. Jeśli tylko znajdziesz te wiersze i zaktualizujesz je lub usuniesz (jak sugestia Cayetano ), nie musisz usuwać innych wierszy ...
Armfoot
@Armfoot - Miałem ten problem podczas dodawania pierwszego wiersza do tabeli za pomocą klucza obcego. Więc nie miałem żadnych wierszy do wyszukiwania.
Krewetka
16

Dla mnie ten problem był nieco inny i bardzo łatwy do sprawdzenia i rozwiązania.

Musisz upewnić się, że OBA twoich stołów to InnoDB. Jeśli jedna z tabel, a mianowicie tabela referencyjna, to MyISAM, ograniczenie się nie powiedzie.

    SHOW TABLE STATUS WHERE Name =  't1';

    ALTER TABLE t1 ENGINE=InnoDB;
zmonteca
źródło
14

Dzieje się tak również podczas ustawiania klucza obcego na parent.id na child.column, jeśli child.column ma już wartość 0 i brak wartości parent.id wynosi 0

Musisz upewnić się, że każda kolumna child.column ma wartość NULL lub ma wartość istniejącą w pliku parent.id

A teraz, kiedy przeczytałem oświadczenie, które napisałem, to właśnie to potwierdza.

fyrye
źródło
14

Miałem dzisiaj ten sam problem. Testowałem na cztery rzeczy, niektóre z nich już tu wspomniano:

  1. Czy w kolumnie podrzędnej są jakieś wartości, które nie istnieją w kolumnie nadrzędnej (oprócz NULL, jeśli kolumna podrzędna ma wartość zerową)

  2. Czy kolumny podrzędne i nadrzędne mają ten sam typ danych?

  3. Czy istnieje indeks w kolumnie nadrzędnej, do której się odwołujesz? MySQL wydaje się tego wymagać ze względu na wydajność ( http://dev.mysql.com/doc/refman/5.5/en/create-table-foreign-keys.html )

  4. A ten rozwiązał dla mnie: Czy obie tabele mają identyczne zestawienie?

Miałem jeden stół w UTF-8, a drugi w iso-coś. To nie zadziałało. Po zmianie tabeli izo-tabeli na sortowanie UTF-8 ograniczenia można dodawać bez problemów. W moim przypadku phpMyAdmin nawet nie pokazał tabeli potomnej w izo-kodowaniu w menu rozwijanym do utworzenia ograniczenia klucza obcego.

Michael Helwig
źródło
7

Wygląda na to, że w linii 0 kolumny jest nieprawidłowa wartość, która nie jest prawidłowym kluczem obcym, więc MySQL nie może ustawić dla niej ograniczenia klucza obcego.

Możesz wykonać następujące kroki:

  1. Upuść kolumnę, dla której próbujesz ustawić ograniczenie FK.

  2. Dodaj go ponownie i ustaw wartość domyślną na NULL.

  3. Spróbuj ponownie ustawić dla niego ograniczenie klucza obcego.

Milad Rahimi
źródło
5

Miałem ten sam problem, sprawdziłem wiersze moich tabel i stwierdziłem, że istnieje pewna niezgodność z wartością pól, które chciałem zdefiniować klucz obcy. Poprawiłem tę wartość, spróbowałem ponownie i problem został rozwiązany.

Mostafa -T
źródło
4

W końcu usuwam wszystkie dane z mojej tabeli i ponownie uruchamiam alter. To działa. Nie jest to genialne, ale oszczędza dużo czasu, zwłaszcza że twoja aplikacja jest wciąż w fazie rozwoju bez żadnych danych klientów.

VHanded
źródło
4

Spróbuj tego

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
źródło
2

Miałem ten sam problem około trzy razy. W każdym przypadku było tak, ponieważ jeden (lub więcej) moich rekordów nie był zgodny z nowym kluczem obcym. Możesz spróbować zaktualizować swoje istniejące rekordy, aby przestrzegać ograniczeń składni klucza obcego przed próbą dodania samego klucza. Poniższy przykład powinien ogólnie izolować rekordy problemów:

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

powtórz AND (candidate key) <> (next proposed foreign key value)w zapytaniu dla każdej wartości w kluczu obcym.

Jeśli masz mnóstwo rekordów, może to być trudne, ale jeśli twój stół jest dość mały, nie powinno to zająć zbyt długo. Nie jestem super niesamowita w składni SQL, ale zawsze to dla mnie izolowało problem.

mopsyd
źródło
2

Opróżnij dane obu tabel i uruchom polecenie. To będzie działać.

vijayrana
źródło
VHanded udzielił tej samej odpowiedzi 3 lata temu. Miejmy nadzieję, że w tabelach nie było żadnych ważnych danych ...
xlecoustillier,
1

Przygotowywałem te rozwiązania i ten przykład może pomóc.

Moja baza danych ma dwie tabele (e-mail i karta kredytowa) z kluczami podstawowymi dla ich identyfikatorów. Inna tabela (klient) określa te tabele jako klucze obce. Mam powód, aby mieć ten e-mail oprócz danych klienta.

Najpierw wstawiam dane wiersza dla tabel, do których istnieją odniesienia (e-mail, karta kredytowa), a następnie dostajesz identyfikator dla każdej, te identyfikatory są potrzebne w trzeciej tabeli (klient).

Jeśli nie wstawisz najpierw wierszy w tabelach, do których się odwołujesz, MySQL nie będzie w stanie wykonać korespondencji, gdy wstawisz nowy wiersz w trzeciej tabeli, która odwołuje się do kluczy obcych.

Jeśli najpierw wstawisz wiersze, do których istnieją odwołania, a następnie wiersz odnoszący się do kluczy obcych, nie wystąpi błąd.

Mam nadzieję że to pomoże.

Substancja MX
źródło
mysql> wstaw do wartości e-mail (e-mail) („[email protected]”); mysql> wstaw do wartości ndtc (ndtc, rok, miesiąc) („1111222233334444”, „2000”, „01”); mysql> wstaw do wartości cliente (nombres, apellidos, telefono, idNDTC, idEmail) („moja nazwa”, „moja aplikacja”, „5555555555”, 1,1);
Substancja
1

Upewnij się, że wartość znajduje się w drugiej tabeli, w przeciwnym razie pojawi się ten błąd w przypisanej odpowiedniej kolumnie.

Jeśli więc jest przypisana, kolumna jest przypisana do identyfikatora wiersza innej tabeli, upewnij się, że w tabeli znajduje się wiersz, w przeciwnym razie pojawi się błąd.

Kingsley Mitchell
źródło
1

możesz spróbować tego przykładu

 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;

Uwaga: jeśli używasz phpmyadmin, odznacz opcję Włącz sprawdzanie klucza obcego

jako przykład wprowadź opis zdjęcia tutaj

mam nadzieję, że to rozwiązanie naprawi problem :)

Fouad Mekkey
źródło
1

Musisz tylko odpowiedzieć na jedno pytanie:

Czy twoja tabela już przechowuje dane? (Zwłaszcza tabela zawiera klucz obcy.)

Jeśli odpowiedź brzmi „tak”, jedyne, co musisz zrobić, to usunąć wszystkie rekordy, a następnie możesz dodać dowolny klucz obcy do swojej tabeli.

Instrukcja usuwania: Z podrzędnego (które obejmuje tabelę kluczy obcych) do tabeli nadrzędnej.

Powód, dla którego nie można dodać klucza obcego po wprowadzeniu danych, wynika z niespójności tabeli. Jak sobie poradzisz z nowym kluczem obcym w poprzedniej tabeli wypełnionej danymi?

Jeśli odpowiedź brzmi „nie”, postępuj zgodnie z innymi instrukcjami.

nikt
źródło
0
UPDATE sourcecodes_tags
SET sourcecode_id = NULL
WHERE sourcecode_id NOT IN (
  SELECT id FROM sourcecodes);

powinno pomóc pozbyć się tych identyfikatorów. Lub jeśli nullnie jest dozwolone sourcecode_id, usuń te wiersze lub dodaj brakujące wartości do sourcecodestabeli.

naXa
źródło
0

Miałem ten sam problem i znalazłem rozwiązanie, umieszczając NULLzamiast NOT NULLna kolumnie klucza obcego. Oto zapytanie:

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 wykonał to zapytanie!

akelec
źródło
0

W moim przypadku utworzyłem nową tabelę o tej samej strukturze, utworzyłem relacje z innymi tabelami, następnie wyodrębniłem dane w CSV ze starej tabeli, która ma problem, a następnie zaimportowałem CSV do nowej tabeli i wyłączyłem sprawdzanie klucza obcego i wyłączono przerwanie importu, wszystkie moje dane są wstawiane do nowej tabeli, która nie ma problemu, a następnie usuwają starą tabelę.

To zadziałało dla mnie.

Shamal Sabah
źródło