Переместить строки между таблицами в SQL - PullRequest
5 голосов
/ 18 ноября 2008

У меня есть 2 таблицы, активная таблица и неактивная таблица. Я хочу переместить строки из активной в неактивную таблицу. Моя первая мысль была

insert into inactive select * from active where ...
delete from active active where ...

Однако, примерно через .42 секунды, я заметил, что это будет пропускать / дублировать строки, если обновления изменяют то, что выбирает предложение where.

В этом случае я легко могу предотвратить это, но что мне делать в тех случаях, когда я не могу?

edit: Судя по ответам, нет простого / тривиального способа сделать это. Я действительно удивлен этим. Я думаю, что было бы несколько существенных преимуществ, если бы оно было.

Ответы [ 8 ]

8 голосов
/ 19 ноября 2008

Флаги статуса вашего друга.

UPDATE old_data SET move="MARKED";
INSERT INTO somewhere... SELECT where move="MARKED";
DELETE FROM old_data WHERE move="MARKED";

Если вы сделаете это с отключенным автокоммитом, повсеместно будут блокироваться блокировки.

Вы можете выполнить COMMIT после каждого шага, если хотите сделать чуть меньше блокировки.

4 голосов
/ 19 ноября 2008

Поддерживает ли ваша база данных предложение OUTPUT? Тогда это может быть идеальным и простым для вас решением, не так ли?

http://msdn.microsoft.com/en-us/library/ms177564.aspx

delete active with (readpast)
output DELETED.*
into inactive
where ...
4 голосов
/ 19 ноября 2008

(по крайней мере, в MS SQL) вы можете использовать транзакции и подсказки блокировки:

begin tran

insert into inactive
select * from active with (updlock)
where ...

delete from active
where ...

commit tran

Без подсказки о блокировке (при обновлении) могут возникать взаимоблокировки, если кто-либо изменяет удаляемые записи.

1 голос
/ 19 ноября 2008

Либо используйте уникальный столбец идентификатора, например

delete from active where rowid in (select rowid in inactive)

или

delete from active as a 
where exists (select * 
              from inactive 
              where pkfld1=a.pkfld1 
              and pkfld2=a.pkfld2)

Кроме того, не забудьте включить этот процесс в транзакцию.

Удачи.

1 голос
/ 19 ноября 2008

Объявите локальную таблицу var и поместите туда значения, вставьте их в неактивную таблицу, затем удалите строки из активной таблицы, которые находятся в вашем локальном списке.

Идея транзакции работает так же хорошо, хотя и тоже.

1 голос
/ 19 ноября 2008

Если вы можете заблокировать строки пессимистично, то есть, когда вы читаете их, чтобы скопировать их в неактивную таблицу, то никто не сможет изменить их из-под вас.

Способ блокировки строк зависит от марки базы данных, и вы не указываете это в своем вопросе.

0 голосов
/ 19 ноября 2008

Почему у вас две таблицы, а не столбец для "IsActive"?

0 голосов
/ 19 ноября 2008

Вот как я сохраняю свои предложения where:

DECLARE @MyTable TABLE
(
  TheKey int PRIMARY KEY
)
--
INSERT INTO @MyTable(TheKey)
SELECT TheKey FROM SourceTable WHERE rows I want
--
INSERT INTO Inactive(fieldlist)
SELECT fieldlist
FROM Active
WHERE TheKey IN (SELECT TheKey FROM @MyTable)
--
DELETE
FROM Active
WHERE TheKey IN (SELECT TheKey FROM @MyTable)

Если вам нужно больше, чем это, вам нужно посмотреть на блокировку (заблокировать изменения во время транзакции).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...