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

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;

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;

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.


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.


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;

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.


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.


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.


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.


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.


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;

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.


2

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


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.


mysql> wstaw do wartości e-mail (e-mail) („xxx@yyy.com”); 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.


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 :)


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.


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.


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!


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.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.