我有2个表,一个活动表和一个非活动表。我想将行从活动表移动到非活动表。我的第一个想法是
insert into inactive select * from active where ...
delete from active active where ...
然而大约.42秒后,我注意到如果更新改变了where子句选择的内容,这将删除/复制行。
在这种情况下,我可以很容易地防止这种情况,但在我无法做到的情况下该怎么办?
编辑:从答案来看,似乎没有简单/琐碎的方法来做到这一点。我对此感到很惊讶。我认为拥有它会有一些实质性的好处。
答案 0 :(得分:8)
状态标志是你的朋友。
UPDATE old_data SET move="MARKED";
INSERT INTO somewhere... SELECT where move="MARKED";
DELETE FROM old_data WHERE move="MARKED";
如果在关闭Autocommit的情况下执行此操作,它将占用整个地方的锁定。
如果你想减少锁定,你可以在每一步之后进行COMMIT。
答案 1 :(得分:4)
(至少在MS SQL中)您可以使用事务和锁定提示:
begin tran
insert into inactive
select * from active with (updlock)
where ...
delete from active
where ...
commit tran
如果没有锁定提示(updlock),可能会发生死锁,如果有人确实更改了被删除的记录。
答案 2 :(得分:4)
您的数据库是否支持OUTPUT子句?那么这对你来说可能是一个完美且易于理解的解决方案,不是吗?
http://msdn.microsoft.com/en-us/library/ms177564.aspx
delete active with (readpast)
output DELETED.*
into inactive
where ...
答案 3 :(得分:1)
如果您可以悲观地锁定行,那就是当您阅读它们以将它们复制到非活动表中时,那么没有人可以将它们从您下面更改出来。
锁定行的方法因数据库品牌而异,您不在问题中指定。
答案 4 :(得分:1)
声明一个本地表var并将值放入那里,将它们插入到非活动表中,然后从活动表中删除本地列表中的行。
交易理念也同样适用。
答案 5 :(得分: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)
另外,不要忘记在事务中包装此进程。
祝你好运。答案 6 :(得分: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)
如果您需要比这更强大,您需要查看锁定(在交易期间阻止更改)。
答案 7 :(得分:0)
为什么你有两个表,而不是“IsActive”的列?