5

我有 2 个表,一个活动表和一个非活动表。我想行从活动表移动到非活动表。我的第一个想法是

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

但是大约 0.42 秒后,我注意到如果更新改变了 where 子句选择的内容,这将删除/重复行。

在这种情况下,我可以很容易地防止这种情况发生,但如果我不能,我该怎么办?

编辑:从答案看来,没有一种简单/简单的方法可以做到这一点。我对此感到非常惊讶。我认为拥有它会有一些实质性的好处。

4

8 回答 8

8

状态标志是您的朋友。

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

如果您在关闭 Autocommit 的情况下执行此操作,它将在所有地方占用锁。

如果你想少做一点锁定,你可以在每一步之后提交。

于 2008-11-18T21:01:46.297 回答
4

(至少在 MS SQL 中)您可以使用事务和锁定提示:

begin tran

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

delete from active
where ...

commit tran

如果有人确实更改了正在删除的记录,则可能会出现没有锁定提示(updlock)的死锁。

于 2008-11-18T21:03:26.137 回答
4

您的数据库是否支持 OUTPUT 子句?那么这对您来说可能是一个完美且易于遵循的解决方案,不是吗?

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

delete active with (readpast)
output DELETED.*
into inactive
where ...
于 2008-11-19T14:38:32.793 回答
1

如果您可以悲观地锁定行,即在您读取它们以将它们复制到非活动表中时,那么没有人可以将它们从您下面更改出来。

锁定行的方法因数据库品牌而异,您没有在问题中指定。

于 2008-11-18T21:04:20.613 回答
1

声明一个本地表 var 并将值放入其中,将它们插入到非活动表中,然后从活动表中删除本地列表中的行。

交易的想法也同样有效。

于 2008-11-18T21:05:08.053 回答
1

要么使用唯一的 id 列,如

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)

另外,不要忘记将此过程包装在事务中。

祝你好运。

于 2008-11-18T21:06:16.473 回答
0

这就是我保留 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)

如果您需要比这更强大,则需要查看锁定(在事务期间阻止更改)。

于 2008-11-18T21:14:37.470 回答
0

为什么你有两个表,而不是“IsActive”列?

于 2008-11-18T21:43:53.543 回答