1

If I have a Postgresql db schema for a tires table like this (a user has many tires):

user_id integer
description text
size integer
color text
created_at timestamp

and I want to enforce a constraint that says "a user can only have 4 tires".

A naive way to implement this would be to do:

SELECT COUNT(*) FROM tires WHERE user_id='123'

, compare the result to 4 and insert if it's lower than 4. It's suspectible to race conditions and so is a naive approach.

I don't want to add a count column. How can I do this (or can I do this) using an exclusion constraint? If it's not possible with exclusion constraints, what is the canonical way?

Marth
  • 23,920
  • 3
  • 60
  • 72
Nona
  • 5,302
  • 7
  • 41
  • 79

1 Answers1

0

The "right" way is using locks here. Firstly, you need to lock related rows. Secondly, insert new record if a user has less than 4 tires. Here is the SQL:

begin;

-- lock rows
select count(*)
from tires
where user_id = 123
for update;

-- throw an error of there are more than 3

-- insert new row
insert into tires (user_id, description)
values (123, 'tire123');

commit;

You can read more here How to perform conditional insert based on row count?

Laurenz Albe
  • 209,280
  • 17
  • 206
  • 263
Artur
  • 628
  • 5
  • 15
  • 1
    There is a correct answer lurking in what you wrote. The `SELECT ... FOR UPDATE` should be on `user_id`, and the recheck in the `INSERT` is unnecessary. – Laurenz Albe Mar 06 '20 at 07:06