Postgresql – the best solution to prevent picking the same value (by multiple requests)

postgresqlselecttransactionupdate

Situation: there is a table "Tours" which contains a lot of generated records with different properties (Color, Priority, PickedUp). The goal is to allow external application (over REST API) to pick up next tour with highest priority for the given color.

This is easy, but the challenge is to completely prevent picking up the same tour multiple times, which can surely happen in live system.

Current approach is:

  • SELECT tour_id based on (color, priority, pickedUp = false)
  • UPDATE tour set PickedUp=true
  • Return tour_id to the calling application

Obviously, since we have SELECT and UPDATE as separate requests, another request can come at this time and pick up the same tour.

I know it's possible to have a single UPDATE + SELECT query, but: I still need to return the picked up tour_id to the caller, how would I do this? Is it possible with SQL to execute SELECT after UPDATE + SELECT in one query?

Best Answer

There are several approaches, but a simple one in pseudo code is:

Retry:
    SELECT tour_id based on (color, priority, pickedUp = false)
    if none selected, then no vacancy error
    UPDATE tour set PickedUp=true where tour_id=:tour_id and PickedUp=false
    If none updated, then retry
Do something with :tour_id

But pickedUp should probably be more than a boolean, recording who picked up the tour. Otherwise if the "Do something" fails then the tour will appear booked in the database, but no one will know why.