No se puede eliminar o actualizar una fila principal: falla una restricción de clave externa

170

Al hacer:

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

Errores:

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

Aquí están mis tablas:

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
fuente

Respuestas:

108

Tal como está, debe eliminar la fila de la tabla de anunciantes antes de poder eliminar la fila en la tabla de trabajos a la que hace referencia. Esta:

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

... es en realidad lo contrario de lo que debería ser. Tal como están las cosas, significa que tendría que tener un registro en la tabla de trabajos antes que los anunciantes. Entonces necesitas usar:

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

Una vez que corrija la relación de clave externa, su declaración de eliminación funcionará.

Ponis OMG
fuente
3
En la primera línea: ¿no crees que debería ser "que hace referencia" en lugar de "que lo hace referencia"? ¿O he entendido mal cómo se supone que funciona la terminología de referencias?
Abraham Philip
66
@AbrahamPhilip Estaba pensando lo mismo. anunciantes referencias de trabajos.
keyser
270

La manera simple sería deshabilitar la verificación de clave externa; realice los cambios y luego vuelva a habilitar la verificación de clave externa.

SET FOREIGN_KEY_CHECKS=0; -- to disable them
SET FOREIGN_KEY_CHECKS=1; -- to re-enable them
Alino Manzi
fuente
171
Esta no es una solución al problema, sino más bien una solución sucia que puede no ser deseable.
madfriend
20
En mi caso: acabo de ejecutar un archivo SQL grande y una de las declaraciones finales falló, así que solo quiero eliminar todas las tablas, corregir el error de sintaxis y volver a ejecutar, haciendo que esto sea exactamente lo que estaba buscando.
ekerner
1
Si iba a hacer esto, ¿por qué no simplemente eliminar todas las restricciones?
Sablefoste
1
Es útil cuando se hace algo como:REPLACE INTO tab_with_constraint ...
Maciek Łoziński
55
La única razón para votar a favor de esta respuesta es si solo desea que su código deje de gritarle y se adentre en el espagueti sin comprender el código que está escribiendo. La razón para tener claves externas en primer lugar es hacer cumplir la integridad referencial. Si necesita deshabilitarlos para que su código se cierre, probablemente quiera repensar sus claves foráneas, en lugar de deshabilitarlas.
cytinus
38

Bajo su diseño actual (posiblemente defectuoso), debe eliminar la fila de la tabla de anunciantes antes de poder eliminar la fila en la tabla de trabajos a la que hace referencia.

Alternativamente, puede configurar su clave externa de modo que una eliminación en la tabla primaria haga que las filas en las tablas secundarias se eliminen automáticamente. Esto se llama una eliminación en cascada. Se parece a esto:

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

Dicho esto, como ya han señalado otros, su clave externa parece que debería ser al revés ya que la tabla de anunciantes realmente contiene la clave principal y la tabla de trabajos contiene la clave externa. Lo reescribiría así:

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

Y la eliminación en cascada no será necesaria.

Asaph
fuente
18

Si desea soltar una tabla, debe ejecutar la siguiente consulta en un solo paso

SET FOREIGN_KEY_CHECKS = 0; DROP TABLE nombre_tabla;

Abin John
fuente
13

Probé la solución mencionada por @Alino Manzi pero no funcionó para mí en las tablas relacionadas con WordPress usando wpdb.

luego modifiqué el código como se muestra a continuación y funcionó

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
fuente
6

Creo que su clave externa está al revés. Tratar:

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

Si hay más de un trabajo con el mismo ID_anunciante, su clave externa debe ser:

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

De lo contrario (si es al revés en su caso), si desea que las filas en el anunciante se eliminen automáticamente si se elimina la fila en el trabajo, agregue la opción 'BORRAR CASCADA' al final de su clave externa:

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

Consulte las restricciones de clave externa

Usuario SO
fuente
3

Debe eliminarlo por orden. Hay dependencia en las tablas

Ran Adler
fuente
2

Cuando crea una base de datos o crea tablas

Debe agregar esa línea en la secuencia de comandos superior crear base de datos o tabla

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

¿Ahora quieres eliminar registros de la tabla? entonces escribes como

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

¡Buena suerte!

Quy Le
fuente
2

¿Qué tal esta alternativa que he estado usando: permita que la clave foránea sea NULL y luego elija ON DELETE SET NULL ?

Personalmente, prefiero usar " ON UPDATE CASCADE " y " ON DELETE SET NULL " para evitar complicaciones innecesarias, pero en su configuración es posible que desee un enfoque diferente. Además, anular valores de clave externa puede provocar complicaciones, ya que no sabrá exactamente qué sucedió allí. Por lo tanto, este cambio debe estar en estrecha relación con el funcionamiento del código de su aplicación.

Espero que esto ayude.

Marius Cucuruz
fuente
2

He tenido este problema en la migración laravel también
el orden de las tablas de caída en hacia abajo () Método sí importa

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

puede no funcionar, pero si cambia el orden, funciona.

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

si necesita dar soporte al cliente lo antes posible y no tiene acceso a

FOREIGN_KEY_CHECKS

para que la integridad de los datos se pueda deshabilitar:

1) eliminar clave foránea

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

2) active su operación de eliminación a través de sql o api

3) agregue la clave externa de nuevo al esquema

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

sin embargo, es una solución urgente, por lo que es bajo su propio riesgo, ya que la falla principal de dicho enfoque es que luego es necesario mantener la integridad de los datos manualmente.

Oleksii Kyslytsyn
fuente
0

Puede crear un activador para eliminar las filas a las que se hace referencia antes de eliminar el trabajo.

    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
fuente
0

El principal problema con este error Error Code: 1451. Cannot delete or update a parent row: a foreign key constraint failses que no le permite saber qué tabla contiene la falla FK, por lo que es difícil resolver el conflicto.

Si usa MySQL o similar, descubrí que puede crear un diagrama ER para su base de datos, luego puede revisar y eliminar de forma segura cualquier conflicto que desencadene el error.

  1. Use MySQL Workbench
  2. Haga clic en Base de datos -> Ingeniería inversa
  3. Seleccione un correcto connection
  4. Siguiente hasta el final, recuerde seleccionar databasey tablesque necesita examinar
  5. Ahora tiene el diagrama ER, puede ver qué tabla tiene conflicto FK
Ng Sek Long
fuente
0

Básicamente, la razón detrás de este tipo de error es que eventualmente está tratando de eliminar una tupla que tiene una clave primaria (tabla raíz) y esa clave primaria se usa en la tabla secundaria como clave externa. En este escenario para eliminar los datos de la tabla primaria, debe eliminar los datos de la tabla secundaria (en los que se usa la clave externa). Gracias

kishan99
fuente
0

Esto me sucedió a mí también y debido a una dependencia y referencia de otras tablas, no pude eliminar la entrada. Lo que hice fue agregar una columna de eliminación (de tipo booleano) a la tabla. El valor en ese campo muestra si el elemento está marcado para su eliminación o no. Si está marcado para eliminación, no busque / use; de lo contrario, úsalo.

Tariq Kamal
fuente
-1

Tal vez deberías probar ELIMINAR CASCADA


fuente
34
Agregar ciegamente una eliminación en cascada (que destruirá los datos) sin comprender el problema es lo peor que se puede hacer.
Tom H