SQL — Update-select in ONE query
Select a batch of records while simultaneously updating them
This article will show you how to both update and select records simultaneously within a single query. This technique is especially practical for processing batches of records that have a state since it ensures you only select every record once. Among the advantages of the update-select are:
- Atomic: this statement either executes both the select and the update succeed or nothing. No change of updating records that are not processed or selecting records that have the wrong status.
- Performance: your database only has to perform one operation in stead of multiple separate ones
- Coolness: impress others with this awesome query
We’ll demonstrate the power of this query through a practical example. First we’ll set up some tables and fill them with data.
0. Goal
You run a business that allows your users to write comics and submit them to a publication(magazines or newspapers e.g.). Before a comic gets published, the publication have to approve of the comic. Since they are very busy people it can take some time for a comic to be approved.
We’ve decided to keep track of the progress of a comic in a table called ComicStatus. This table contains the ComicName, the Publication and the State of the comic. The State reflects the comic’s state in the process of processing, submitting and acceptance or rejection by the publication. Let’s set up our table.
Every few minutes we run a process that does the following:
- Take all new comics and submit them
- Take submitted comics and check if the publication has processed them yet
- If a comic is processed: update status to either accepted or rejected
Now let’s see how the select-update can help us with improving our process.
2. Selecting records in batches while updating status
We’ve decided to limit the process to a maximum of 5 comics at a time for development purposes. We’ll start with the most obvious way of handling this problem and then slowly improve it.
1 . The dumb way
Imagine we run our process every minute in the following way:
- Select top 5 records new records (with status 0)
- Loop through all of the records and submit each one to their publication
- wait for the publication API’s to approve of the comic
- update the comic’s status to either accepted or rejected
Since our process runs every minute, and approving the comic can take more than a minute, there is a change we select the same record twice. This can easily be fixed by quickly updating the status.
2. The better way
Before submitting the records we update the status of the selected records
- Select top 5 records new records (with status 0)
- Update top 5 of the selected records to status 1 (in process)
- Loop through all of the records and submit each one to their publication
- wait for the publication API’s to return a result
- update the comic’s status to either accepted or rejected
This way can still give an error. What if new records get inserted in our table between step 1 and 2? If this is the case we update unprocessed records and miss updating processed records.
3. The update-select way
We select the records we want and in the same query update their status.
- Update the top 5 records new records (with status 0) AND select them
- Loop through all of the records and submit each one to their publication
- wait for the publication API’s to return a result
- update the comic’s status to either accepted or rejected
This way ensures we don’t process records more than once. It doesn’t matter how long our process runs and when new records get inserted. How to perform step 1? Easier than you think:
That’s it! Pretty short right? We first update the top 2 records where the status is 0 and then output them. This output works like a regular select. Try to execute this query multiple times in a row; you’ll notice that you will never select the same record twice since it updates the status first. It will batch through our records until there are no more records with status 0.
Conclusion
Using this Update-Select ensures that we only update the records we’ve selected for processing and guarantees that either both succeed or the whole operation fails. It is a great new tool in your toolbelt just like these:
- DELETE INTO another table
- UPDATE INTO another table
- Insert, delete and update in ONE statement
- Roll back queries using transactions
- Version control your database
- Docker for absolute beginners
Happy coding!
— Mike
P.S: like what I’m doing? Follow me!