Nie można usunąć ani zaktualizować wiersza nadrzędnego: ograniczenie klucza obcego kończy się niepowodzeniem

170

Robiąc:

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

Błędy IT:

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

Oto moje tabele:

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

Odpowiedzi:

108

W obecnej sytuacji musisz usunąć wiersz z tabeli reklamodawców, zanim będzie można usunąć wiersz z tabeli ofert pracy, do którego się on odnosi. To:

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

... jest właściwie przeciwieństwem tego, czym powinno być. W rzeczywistości oznacza to, że musiałbyś mieć zapis w tabeli ofert pracy przed reklamodawcami. Więc musisz użyć:

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

Po poprawieniu relacji klucza obcego instrukcja usuwania będzie działać.

Kucyki OMG
źródło
3
W pierwszym wierszu: czy nie uważasz, że powinno być „że się odnosi” zamiast „że się do niego odnosi”? A może źle zrozumiałem, jak powinna działać terminologia związana z referencjami?
Abraham Philip
6
@AbrahamPhilip Myślałem o tym samym. reklamodawcy odnoszą się do ofert pracy.
keyser
270

Prostym sposobem byłoby wyłączenie sprawdzania klucza obcego; wprowadź zmiany, a następnie ponownie włącz sprawdzanie klucza obcego.

SET FOREIGN_KEY_CHECKS=0; -- to disable them
SET FOREIGN_KEY_CHECKS=1; -- to re-enable them
Alino Manzi
źródło
171
To nie jest rozwiązanie problemu, ale raczej brudne obejście, które może nie być pożądane.
madfriend
20
W moim przypadku: właśnie uruchomiłem duży plik SQL i jedno z końcowych instrukcji nie powiodło się, więc chcę tylko usunąć wszystkie tabele, naprawić błąd składni i uruchomić ponownie, dzięki czemu jest dokładnie to, czego szukałem.
ekerner
1
Jeśli miałeś to zrobić, dlaczego po prostu nie usunąć wszystkich ograniczeń?
Sablefoste
1
Przydaje się przy robieniu czegoś takiego jak:REPLACE INTO tab_with_constraint ...
Maciek Łoziński
5
Jedynym powodem, dla którego warto głosować za tą odpowiedzią, jest to, że po prostu chcesz, aby Twój kod przestał na ciebie krzyczeć i wbił się głębiej w spaghetti bez zrozumienia kodu, który piszesz. Powodem posiadania kluczy obcych na pierwszym miejscu jest wymuszenie integralności referencyjnej. Jeśli chcesz je wyłączyć, aby zamknąć kod, prawdopodobnie chcesz ponownie przemyśleć klucze obce, zamiast je wyłączać.
cytinus
38

Zgodnie z obecnym (prawdopodobnie wadliwym) projektem, musisz usunąć wiersz z tabeli reklamodawców, zanim będzie można usunąć wiersz z tabeli ofert pracy, do którego się on odnosi.

Alternatywnie możesz skonfigurować swój klucz obcy w taki sposób, aby usunięcie w tabeli nadrzędnej powodowało automatyczne usuwanie wierszy w tabelach podrzędnych. Nazywa się to usuwaniem kaskadowym. Wygląda mniej więcej tak:

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

Powiedziawszy to, jak inni już zauważyli, wydaje się, że twój klucz obcy powinien działać odwrotnie, ponieważ tabela reklamodawców naprawdę zawiera klucz podstawowy, a tabela ofert pracy zawiera klucz obcy. Przepisałbym to tak:

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

Kaskadowe usuwanie nie będzie konieczne.

Asaf
źródło
18

Jeśli chcesz usunąć tabelę, wykonaj następujące zapytanie w jednym kroku

SET FOREIGN_KEY_CHECKS = 0; DROP TABLE nazwa_tabeli;

Abin John
źródło
13

Wypróbowałem rozwiązanie wspomniane przez @Alino Manzi, ale nie działało ono dla mnie na tabelach związanych z WordPressem przy użyciu wpdb.

potem zmodyfikowałem kod jak poniżej i zadziałało

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

Myślę, że twój klucz obcy jest odwrócony. Próbować:

ALTER TABLE 'jobs'
ADD CONSTRAINT `advertisers_ibfk_1` FOREIGN KEY (`advertiser_id`) REFERENCES `advertisers` (`advertiser_id`)
Tom H.
źródło
5

Jeśli istnieje więcej niż jedna oferta pracy z tym samym identyfikatorem reklamodawcy, klucz obcy powinien mieć postać:

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

W przeciwnym razie (jeśli w Twoim przypadku jest odwrotnie), jeśli chcesz, aby wiersze w reklamodawcy były automatycznie usuwane, jeśli wiersz w zadaniu zostanie usunięty, dodaj opcję „USUŃ KASKADĘ” na końcu klucza obcego:

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

Sprawdź ograniczenia klucza obcego

Użytkownik SO
źródło
3

Musisz go usunąć według kolejności. W tabelach występują zależności

Ran Adler
źródło
2

Podczas tworzenia bazy danych lub tworzenia tabel

Należy dodać tę linię u góry skryptu tworzącego bazę danych lub tabelę

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

Teraz chcesz usunąć rekordy z tabeli? wtedy piszesz jako

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

Powodzenia!

Quy Le
źródło
2

A co z tą alternatywą, której używałem: pozwól, aby klucz obcy miał wartość NULL, a następnie wybierz ON DELETE SET NULL .

Osobiście wolę używać zarówno opcji „ ON UPDATE CASCADE ”, jak i „ ON DELETE SET NULL ”, aby uniknąć niepotrzebnych komplikacji, ale w konfiguracji możesz chcieć innego podejścia. Ponadto zerowanie wartości klucza obcego może prowadzić do komplikacji, ponieważ nie będziesz wiedział, co dokładnie się tam wydarzyło. Więc ta zmiana powinna być ściśle związana z działaniem kodu aplikacji.

Mam nadzieję że to pomoże.

Marius Cucuruz
źródło
2

Miałem ten problem w migracji laravel zbyt
Kolejność tabel spadek w dół () metoda ma znaczenia

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

może nie działać, ale jeśli zmienisz kolejność, zadziała.

Schema::dropIfExists('contact');
Schema::dropIfExists('groups');
Jestem w
źródło
1

jeśli potrzebujesz jak najszybciej wesprzeć klienta, a nie masz do niego dostępu

FOREIGN_KEY_CHECKS

aby można było wyłączyć integralność danych:

1) usuń klucz obcy

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

2) aktywuj operację usuwania poprzez sql lub api

3) dodaj klucz obcy z powrotem do schematu

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

jest to jednak poprawka, więc robisz to na własne ryzyko, ponieważ główną wadą takiego podejścia jest to, że później trzeba ręcznie zachować integralność danych.

Oleksii Kyslytsyn
źródło
0

Możesz utworzyć wyzwalacz, aby usunąć odnośne wiersze przed usunięciem zadania.

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

Główny problem z tym błędem Error Code: 1451. Cannot delete or update a parent row: a foreign key constraint failspolega na tym, że nie informuje on, która tabela zawiera błąd FK, więc trudno jest rozwiązać konflikt.

Jeśli korzystasz z MySQL lub podobnego, dowiedziałem się, że możesz utworzyć diagram ER dla swojej bazy danych, a następnie przejrzeć i bezpiecznie usunąć wszelkie konflikty powodujące błąd.

  1. Użyj Środowiska pracy MySQL
  2. Kliknij Baza danych -> Inżynieria odwrotna
  3. Wybierz poprawną connection
  4. Następnie, aż do końca, pamiętaj, aby wybrać databasei tablessprawdzić
  5. Teraz masz diagram ER, możesz zobaczyć, która tabela ma konflikt FK
Ng Sek Long
źródło
0

Zasadniczo powodem tego typu błędów jest to, że ostatecznie próbujesz usunąć krotkę, która ma klucz podstawowy (tabela główna) i ten klucz podstawowy jest używany w tabeli podrzędnej jako klucz obcy. W tym scenariuszu, aby usunąć dane tabeli nadrzędnej, musisz usunąć dane tabeli podrzędnej (w której używany jest klucz obcy). Dzięki

kishan99
źródło
0

Zdarzyło mi się to również i ze względu na zależność i odniesienie z innych tabel nie mogłem usunąć wpisu. To, co zrobiłem, to dodanie kolumny usuwania (typu boolean) do tabeli. Wartość w tym polu wskazywała, czy element jest oznaczony do usunięcia, czy nie. Jeśli zaznaczono do usunięcia, nie pobieraj / nie używaj; w przeciwnym razie użyj go.

Tariq Kamal
źródło
-1

Może powinieneś spróbować ON DELETE CASCADE


źródło
34
Ślepe dodanie usuwania kaskadowego (które zniszczy dane) bez zrozumienia problemu jest najgorszą rzeczą, jaką można zrobić.
Tom H