2011-10-25 3 views
1

J'ai une table d'enregistrements, qui a une relation d'auto-relation.Mise à jour SQL avec jointure interne

De plus - pour faciliter la recherche - j'ai un drapeau qui détermine qu'un enregistrement a été référencé et donc cette ligne est désormais « obsolète » et est seulement là pour des fins de vérification:

CREATE TABLE Records 
(
    RecordID INT(5) NOT NULL, 
    Replaces INT(5) NULL, 
    Obsolete INT(1) NOT NULL 
) 

RecordID est le PK, Replaces liens vers un précédent RecordID qui a maintenant été remplacé, et Obsolete est une information redondante qui dit juste qu'un autre enregistrement a remplacé celui-ci. Cela rend la recherche beaucoup plus facile. La table est très grande. Ce ne sont que 3 des colonnes.

Le seul problème est: il y avait une faute de frappe dans l'une des requêtes dans le système, donc pour un petit ensemble de lignes, la valeur Obsolète n'a pas été mise à 1 (vrai).

Cette requête affichera tous les enregistrements avec Obsolète égal à 0 qui devrait être égal à 1:

SELECT * 
    FROM Records AS rec1 
LEFT JOIN Records AS rec2 
     ON rec1.Replaces = rec2.RecordID 
    WHERE rec2.RecordID IS NOT NULL 
     AND rec2.Obsolete = 0; 

Maintenant je dois exécuter un UPDATE pour changer tous les req2.Obsolete de 0 à 1, mais Je ne suis pas sûr de savoir comment écrire une requête avec un INNER JOIN.

Répondre

1

Vous n'avez pas besoin d'une jointure interne. Étant donné que votre requête renvoie déjà les dossiers qui doivent être mis à jour, faites ceci:

Update Records 
set Obsolete=1 where 
RecordID in (
SELECT rec2.RecordID  
     FROM Records AS rec1 
LEFT JOIN Records AS rec2 
     ON rec1.Replaces = rec2.RecordID 
    WHERE rec2.RecordID IS NOT NULL 
     AND rec2.Obsolete = 0 
) 
+0

"Vous n'avez pas besoin d'une jointure interne" - si votre "LEFT OUTER JOIN" est sémantiquement équivalent à un "INNER JOIN", cela ne fait-il pas une jointure interne? – onedaywhen

1
UPDATE Records 
SET obsolete = 1 
WHERE recordID in (
SELECT rec1.recordid 
    FROM Records AS rec1 
LEFT JOIN Records AS rec2 
     ON rec1.Replaces = rec2.RecordID 
    WHERE rec2.RecordID IS NOT NULL 
     AND rec2.Obsolete = 0 
) 
0

Je vous conseille de faire cela en deux étapes en utilisant une table temporaire:

-- Create temporary table for holding RecordIDs to be marked as obsolete 
CREATE TEMPORARY TABLE `mark_obsolete` (`RecordID` INT NOT NULL); 

-- Insert RecordIDs to mark as obsolete into temp table 
INSERT INTO `mark_obsolete` (`RecordID`) 
SELECT `rec2`.`RecordID` 
FROM 
    `Records` AS `rec1` 
    INNER JOIN `Records` AS `rec2` 
     ON `rec1`.`Replaces` = `rec2`.`RecordID` 
WHERE `rec2`.`Obsolete` = 0; 

-- Update records using inner join to temp table 
UPDATE 
    `Records` AS `r` 
    INNER JOIN `mark_obsolete` AS `o` 
     ON `r`.`RecordID` = `o`.`RecordID` 
SET `r`.`Obsolete` = 1; 

DROP TEMPORARY TABLE `mark_obsolete`; 

Notez que l'utilisation d'un LEFT JOIN avec WHERE rec2.RecordID IS NOT NULL est identique à INNER JOIN.

La raison de l'utilisation d'une table temporaire est d'éviter les problèmes de verrouillage lors de la mise à jour de la même table utilisée dans la sous-requête. Et il pourrait également vous donner de meilleures performances que l'utilisation de la clause IN.