tags:

views:

70

answers:

2

I have a Data table and an Archive table.

A webapp pours data into the Data table, and a cron job pulls the data out every hour and archives it in the Archive table (this keeps the Data table small and quick to work with).

As I see it there are two psudo-SQL queries to run:

INSERT Archive SELECT * FROM Data;

&

DELETE FROM Data;

However, I only want to delete the data that was successfully copied, if the copy fails I want it to be left in a consistent state, with the data neither half-moved, nor deleted.

What's the right way to do this?

+4  A: 

With a transaction.

begin transaction;
insert into archive select * from data;
delete from data where primary_key in (select primary_key from archive);
commit;
Paul Tomblin
Some database systems aren't consistent on queries during transactions, only on updates, so "delete from data" may or may not delete stuff that was added after the insert, that's why I'm suggesting using a query in the delete.
Paul Tomblin
I think you intended to select from the archive table in the sub-query: `delete from data where primary_key in (select primary_key from archive);`
Ike Walker
Also, `begin transaction` is not a valid MySQL command. The proper command is `start transaction`.
Ike Walker
Thanks very much guys, This sounds like it'll do the trick!
Oatman
A: 

I recommend using the multi-table delete syntax, and joining to the archive table for your delete. That way you only delete rows that are in both tables.

Simple Example:

insert into archive select * from data;
delete data.*
from data
inner join archive on archive.id = data.id;

Beyond that, you may want to consider breaking this down into smaller chunks for better performance. For example:

insert into archive select * from data where id > 1000 and id <= 2000;
delete data.*
from data
inner join archive on archive.id = data.id
where data.id > 1000 and data.id <= 2000;

From the manual: http://dev.mysql.com/doc/refman/5.1/en/delete.html

Ike Walker