Обновление SQL с внутренним объединением - PullRequest
1 голос
/ 25 октября 2011

У меня есть таблица рекордов, в которой есть самоотношения.

Дополнительно - чтобы упростить поиск - у меня есть флаг, который определяет, что на запись была сделана ссылка, и, следовательно, эта строка «устарела» и используется только для целей аудита:

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

RecordID - это PK, Replaces - ссылки на предыдущий RecordID, который теперь заменен, а Obsolete - избыточная информация, которая просто говорит о том, что другая запись заменила эту. Это просто делает поиск намного проще. Стол очень большой. Это только 3 из столбцов.

Единственная проблема: в одном из запросов системы произошла опечатка, поэтому для небольшого набора строк значение «Устаревшее» не было установлено в 1 (true).

Этот запрос покажет все записи с устаревшим значением, равным 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 ]

1 голос
/ 25 октября 2011

Вам не нужно внутреннее соединение.Поскольку ваш запрос уже возвращает записи, которые необходимо обновить, просто сделайте это:

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
)
1 голос
/ 25 октября 2011
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 голосов
/ 25 октября 2011

Я бы предложил сделать это в два этапа, используя временную таблицу:

-- 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 JOIN с WHERE rec2.RecordID IS NOT NULL аналогично INNER JOIN.

Причина использования временной таблицы состоит в том, чтобы избежать проблем с блокировкой при обновлении той же таблицы, которая использовалась в подзапросе. И это также может дать вам лучшую производительность, чем использование предложения IN.

...