views:

2178

answers:

8

I have 2 tables, an active table and an inactive table. I want to move rows from the active to the inactive table. My first thought was

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

However about .42 seconds later I noticed this will drop/duplicate rows if updates alter what the where clause selects.

In this case, I can easily prevent that but what should I do in cases where I can't?

edit: From the answers it look like there isn't an easy/trivial way to do this. I'm really surprised by this. I would think that there would be some substantial benefits to having it.

+5  A: 

Status flags are your friend.

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

If you do this with Autocommit off, it will seize locks all over the place.

You can COMMIT after each step, if you want to do a little less locking.

S.Lott
+4  A: 

(In MS SQL at least) you could use transactions and locking hints:

begin tran

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

delete from active
where ...

commit tran

Without locking hint (updlock) deadlocks may occur, if someone does alter records being deleted.

Arvo
+1  A: 

If you can lock the rows pessimistically, that is as you read them to copy them into the inactive table, then no one can change them out from under you.

The method to lock the rows varies by database brand, and you don't specify that in your question.

Bill Karwin
+1  A: 

Declare a local table var and put the values into there, insert them into your inactive table, then delete the rows from the active table that are in your local list.

The transaction idea works just as well though too.

Nick DeVore
+1  A: 

Either use a unique id column like

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

or

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

Also, don't forget to wrap this process in a transaction.

Good luck.

John MacIntyre
EXISTS isn't entirely MS SQL Server specific - it's SQL-92 standard and I believe it's on MySQL and Oracle as well (somebody correct me if I'm wrong).
Ian Varley
hmmm ... it looks like you are correct. http://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt
John MacIntyre
A: 

This is how I preserve my where clauses:

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)

If you need stronger than this, you'll need to look at locking (block out changes during the transaction).

David B
A: 

Why do you have two tables, rather than a column for "IsActive"?

le dorfier
Table size related performance. IIRC that alone can be a good reason, In my cases because of the way I'm using it, if a query does anything /but/ an index lookup, it /will/ turn into a worst cases lookup (kind of like here http://en.wikipedia.org/wiki/Linear_probing)
BCS
Also: "I'll never be using this code again so why fix what mostly works" ;-)
BCS
OK, agreed. Now we're discussing one of the consequences. Another is the inevitable "find the records WHERE ..." and they might be in either table.A reasonable question might be "is this turning out to be the best way to deal with table size related perf issues?" That's why I'm asking.
le dorfier
Is the table so megahuge that SQL Server is actually unable to store and retrieve on the indexes efficiently enough? The question as presented doesn't suggest that level of sophisticated understanding of the technology.
le dorfier
+2  A: 

Does your database support the OUTPUT Clause? Then this could be a perfect and easy to follow solution for you, couldn't it?

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

delete active with (readpast)
output DELETED.*
into inactive
where ...
Örjan Jämte
I'll have to check, but if it does, that is EXACTLY what I was looking for!! (MySQL in case someone gets to it before I do.)
BCS
What about triggers? In SQL Server I have done a similar task with a trigger on delete that inserted the deleted posts in a history table.
Örjan Jämte