带内连接的SQL Update

时间:2011-10-25 03:35:54

标签: mysql sql inner-join

我有一张记录表,它有自我关系。

此外 - 为了使搜索更容易 - 我有一个标志,确定已经引用了一条记录,因此该行现在已“过时”,仅用于审计目的:

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

RecordID是PK,Replaces链接到之前已被替换的RecordID,而Obsolete是冗余信息,只是说另一条记录已替换了这条记录。它只是让搜索更容易。桌子非常大。这些只是列中的3个。

唯一的问题是:系统中的一个查询中存在拼写错误,因此对于一小组行,Obsolete值未设置为1(true)。

此查询将显示Obsolete等于0且等于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;

现在我需要运行UPDATE将所有req2.Obsolete从0更改为1,但我不确定如何使用INNER JOIN编写查询。

3 个答案:

答案 0 :(得分: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
)

答案 1 :(得分:1)

您不需要内部联接。由于您的查询已经返回了需要更新的记录,请执行以下操作:

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
)

答案 2 :(得分:0)

我建议使用临时表分两步执行此操作:

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

请注意,LEFT JOINWHERE rec2.RecordID IS NOT NULL的使用方式与INNER JOIN相同。

使用临时表的原因是为了避免在更新子查询中使用的同一个表时出现锁定问题。它也可能比使用IN子句提供更好的性能。