2010-11-18 20 views
1

J'ai une base de données qui était à l'origine dans MyISAM et n'avait donc pas de contraintes de clé étrangère. Par conséquent, il existe un certain nombre de lignes orphelines où l'enregistrement auquel la clé étrangère fait référence a été supprimé depuis. Pour corriger cela, j'ai décidé de convertir en InnoDB et d'ajouter les clés étrangères, avec CASCADE pour la mise à jour et la suppression. Cependant, lorsque je tente d'ajouter la clé étrangère, je reçois des erreurs comme ça (de la console Navicat 8):MySQL InnoDB - crée une contrainte de clé étrangère CASCADE lorsque des données existent déjà qui la violent?

1452 - Cannot add or update a child row: a foreign key constraint fails 
(`database`.`#sql-1358_38d`, CONSTRAINT `#sql-1358_38d_ibfk_1` FOREIGN KEY 
(`manufacturerID`) REFERENCES `manufacturer` (`ID`) ON DE) 

Je sais pourquoi il fait cela - parce que des lignes orphelines. Existe-t-il un moyen pour que la création de la contrainte efface automatiquement ces lignes? Il faudra des années pour parcourir toutes les tables et trouver des rangs orphelins.

Ceci est l'une des requêtes que je suis en juste au cas où il est suspect:

ALTER TABLE part_number ADD CONSTRAINT 
FOREIGN KEY(manufacturerID) 
REFERENCES manufacturer(ID) 
ON DELETE CASCADE 
ON UPDATE CASCADE; 

Répondre

2

écrire une requête qui trouve les lignes orphelins, puis l'utiliser pour supprimer. par exemple

SELECT part_number.id FROM part_number LEFT JOIN manufacturer ON (manufacturer.ID = part_number.manufacturerID) where manufacturer.ID IS NULL

+0

Eh bien, c'est essentiellement ce que j'ai commencé à faire, mais ça va prendre un certain temps, me demandais s'il y avait la possibilité de ne pas avoir à le faire manuellement. – Gnuffo1

1

Vous devez vous débarrasser de tous les documents pertinents avant de pouvoir ajouter une contrainte.

Vous pouvez le faire de deux façons.

1 Utilisation existe pas()

DELETE FROM part_number 
WHERE NOT EXISTS (
      select id from manufacturer 
      where part_number.manufacturerID = manufacturer.ID 
     ) 

2. En utilisant une table temporaire (un peu laid, mais je vais le poster aussi)

-- create a temporary table 
CREATE TEMPORARY TABLE `temp_ids` 
(
    `id` INTEGER 
); 

-- store all id's that need to be deleted 
INSERT INTO `temp_ids` 
SELECT part_number.id FROM part_number LEFT JOIN manufacturer ON (manufacturer.ID = part_number.manufacturerID) 
WHERE ISNULL(`manufacturer.ID); 

-- delete them 
DELETE 
FROM part_number 
WHERE id IN (
    SELECT `id` FROM `temp_ids` 
); 

-- drop the table 
DROP TEMPORARY TABLE `temp_ids`; 

Voir ma question connexe: Handling database integrity

Après la suppression de tous les enregistrements "morts", vous pouvez ajouter une contrainte.

espère que cela fonctionne pour vous :)