Impossibile eliminare o aggiornare una riga principale: un vincolo di chiave esterna non riesce


170

Quando si fa:

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

Errori:

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

Ecco i miei tavoli:

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`);

Risposte:


108

Allo stato attuale, è necessario eliminare la riga dalla tabella degli inserzionisti prima di poter eliminare la riga nella tabella dei lavori a cui fa riferimento. Questo:

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

... è in realtà l'opposto di quello che dovrebbe essere. Così com'è, significa che dovresti avere un record nella tabella dei lavori prima degli inserzionisti. Quindi è necessario utilizzare:

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

Dopo aver corretto la relazione di chiave esterna, la dichiarazione di eliminazione funzionerà.


3
Nella prima riga: non pensi che dovrebbe essere "che fa riferimento" anziché "che fa riferimento"? O ho frainteso come dovrebbe funzionare la terminologia dei riferimenti?
Abraham Philip,

6
@AbrahamPhilip Stavo pensando la stessa cosa. inserzionisti fa riferimento a lavori.
keyser

270

Il modo semplice sarebbe disabilitare il controllo della chiave esterna; apportare le modifiche, quindi riattivare il controllo della chiave esterna.

SET FOREIGN_KEY_CHECKS=0; -- to disable them
SET FOREIGN_KEY_CHECKS=1; -- to re-enable them

171
Questa non è una soluzione al problema, ma piuttosto una soluzione sporca che potrebbe non essere desiderata.
madfriend

20
Nel mio caso: ho appena eseguito un file SQL di grandi dimensioni e una delle istruzioni finali non è riuscita, quindi voglio solo eliminare tutte le tabelle, correggere l'errore di sintassi ed eseguire nuovamente, rendendolo esattamente quello che stavo cercando.
ekerner,

1
Se avessi intenzione di farlo, perché non rimuovere tutti i vincoli?
Sablefoste,

1
È utile quando si fa qualcosa del tipo:REPLACE INTO tab_with_constraint ...
Maciek Łoziński,

5
L'unico motivo per votare questa risposta è se vuoi solo che il tuo codice smetta di urlare contro di te e approfondire gli spaghetti senza capire il codice che stai scrivendo. La ragione per avere chiavi esterne in primo luogo è far rispettare l'integrità referenziale. Se è necessario disabilitarli per bloccare il codice, è probabile che si desideri ripensare le chiavi esterne, anziché disabilitarle.
Citino

38

Sotto il tuo attuale design (possibilmente difettoso), devi eliminare la riga dalla tabella degli inserzionisti prima di poter eliminare la riga nella tabella dei lavori a cui fa riferimento.

In alternativa, è possibile impostare la chiave esterna in modo tale che un'eliminazione nella tabella padre causi l'eliminazione automatica delle righe nelle tabelle figlio. Questo si chiama eliminazione a cascata. Sembra qualcosa del genere:

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

Detto questo, come altri hanno già sottolineato, la tua chiave esterna ritiene che dovrebbe andare al contrario poiché la tabella degli inserzionisti contiene davvero la chiave primaria e la tabella dei lavori contiene la chiave esterna. Lo riscriverei in questo modo:

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

E l'eliminazione a cascata non sarà necessaria.


18

Se si desidera eliminare una tabella, è necessario eseguire la query seguente in un unico passaggio

SET FOREIGN_KEY_CHECKS = 0; DROP TABLE table_name;


13

Ho provato la soluzione menzionata da @Alino Manzi ma non ha funzionato per me sulle tabelle relative a WordPress usando wpdb.

poi ho modificato il codice come di seguito e ha funzionato

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

6

Penso che la tua chiave esterna sia al contrario. Provare:

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

5

Se sono presenti più lavori con lo stesso advertiser_id, la chiave esterna dovrebbe essere:

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

Altrimenti (se è il contrario nel tuo caso), se vuoi che le righe nell'inserzionista vengano eliminate automaticamente se la riga nel lavoro viene eliminata aggiungi l'opzione 'ON DELETE CASCADE' alla fine della tua chiave esterna:

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

Scopri i vincoli di chiave esterna


3

È necessario eliminarlo per ordine Ci sono dipendenze nelle tabelle


2

Quando si crea un database o si creano tabelle

Dovresti aggiungere quella riga nella parte superiore dello script per creare database o tabelle

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

Ora vuoi eliminare i record dalla tabella? allora scrivi come

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

In bocca al lupo!


2

Che ne dici di questa alternativa che ho usato: consenti alla chiave esterna di essere NULL e quindi scegli ON DELETE SET NULL .

Personalmente preferisco usare sia " ON UPDATE CASCADE " sia " ON DELETE SET NULL " per evitare inutili complicazioni, ma sul tuo setup potresti voler un approccio diverso. Inoltre, il valore NULL di una chiave esterna può portare a complicazioni poiché non saprai esattamente cosa è successo lì. Quindi questa modifica dovrebbe essere in stretta relazione con il funzionamento del codice dell'applicazione.

Spero che questo ti aiuti.


2

Ho avuto questo problema in migrazione laravel anche
l'ordine delle tabelle goccia in giù () metodo non importa

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

potrebbe non funzionare, ma se si modifica l'ordine, funziona.

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

1

se devi supportare il cliente il prima possibile e non hai accesso a

FOREIGN_KEY_CHECKS

in modo che l'integrità dei dati possa essere disabilitata:

1) elimina chiave esterna

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

2) attiva la tua operazione di cancellazione tramite sql o api

3) aggiungere la chiave esterna allo schema

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

tuttavia, è una correzione rapida, quindi è a proprio rischio, poiché il principale difetto di tale approccio è che è necessario successivamente mantenere l'integrità dei dati manualmente.


0

È possibile creare un trigger per eliminare le righe di riferimento prima di eliminare il processo.

    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 ;

0

Il problema principale con questo errore Error Code: 1451. Cannot delete or update a parent row: a foreign key constraint failsè che non ti consente di sapere quale tabella contiene l'errore FK, quindi è difficile risolvere il conflitto.

Se usi MySQL o simili, ho scoperto che puoi creare un diagramma ER per il tuo database, quindi puoi rivedere e rimuovere in sicurezza tutti i conflitti che causano l'errore.

  1. Usa il banco di lavoro MySQL
  2. Fare clic su Database -> Reverse engineering
  3. Seleziona un corretto connection
  4. Successivamente fino alla fine, ricordati di selezionare databasee tablesche è necessario esaminare
  5. Ora hai il diagramma ER, puoi vedere quale tabella ha un conflitto FK

0

Fondamentalmente, il motivo alla base di questo tipo di errore è che alla fine si sta tentando di eliminare un tupple con chiave primaria (tabella radice) e che la chiave primaria viene utilizzata nella tabella figlio come chiave esterna. In questo scenario per eliminare i dati della tabella padre è necessario rimuovere i dati della tabella figlio (in cui viene utilizzata la chiave esterna). Grazie


0

Questo è successo anche a me e, a causa di una dipendenza e di un riferimento da altre tabelle, non ho potuto rimuovere la voce. Quello che ho fatto è stata aggiunta una colonna di eliminazione (di tipo booleano) alla tabella. Il valore in quel campo mostra se l'elemento è contrassegnato per l'eliminazione o meno. Se contrassegnato per l'eliminazione, non recuperare / utilizzare; altrimenti, usalo.


-1

Forse dovresti provare A CANCELLARE CASCADE


34
Aggiungere alla cieca un'eliminazione a cascata (che distruggerà i dati) senza capire il problema è la cosa peggiore che si possa fare.
Tom H,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.