简体   繁体   中英

Insert data in one table, remove from another, with timestamp condition in mysql

In short

Is there a safe way to move database entries - based on a timestamp condition - to another table (without first querying the time)? So that it is ensured, INSERT INTO works on the exact same entries as DELETE ?

Background to the question

  • This question is not about the importance of using transactions, that is a given! But rather it is about the problem that the time (eg. the value of NOW() ) might be different for the two subsequent queries.
  • Since a programming framework is used, which does (for safety reasons) not allow multiple queries being executed in a single call, this really becomes an issue

Example table structure

Source
---------------------------------------------
ID        |  Timeout              |  Data
---------------------------------------------
1         |  2014-12-31 12:00:00  |  foo
2         |  2014-12-31 15:00:00  |  bar
3         |  2014-12-31 18:00:00  |  foobar

Archive
---------------------------------------------
ID        |  Data
---------------------------------------------

Demonstration (simplified)

<?php

    beginTransaction();
    try {
        // Imagine this happens at 2014-12-31 14:59:59(.992) [Entry #2 not copied]
        execute( "INSERT INTO Archive (ID, Data) 
                      SELECT ID, Data FROM Source
                      WHERE Timeout <= NOW()" );

        // While here it might be already 2014-12-31 15:00:00(.004) [Entry #2 deleted]
        execute("DELTE FROM Source WHERE Timeout <= NOW()");
        commit();
    }
    catch (Exception $e) {
        rollBack();
        return false;
    }

    return;
?>

So is there a safe way to evade this problem, preferably with performance in mind (I know, in this case php might be the wrong language in the first place ^^). Help much appreciated!

execute("SET @now = NOW()");

execute("
    INSERT INTO Archive (ID, Data) 
    SELECT ID, Data 
    FROM Source
    WHERE Timeout <= @now
");

execute("DELTE FROM Source WHERE Timeout <= @now");

OR

execute("
    INSERT INTO Archive (ID, Data) 
    SELECT ID, Data 
    FROM Source
    WHERE Timeout <= NOW()
");

execute("DELTE FROM Source WHERE Timeout <= (SELECT MAX(Timeout) FROM Archive)");

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM