使用 Postgres 排除约束限制匹配特定条件的表行数?

Posted

技术标签:

【中文标题】使用 Postgres 排除约束限制匹配特定条件的表行数?【英文标题】:Cap on number of table rows matching a certain condition using Postgres exclusion constraint? 【发布时间】:2020-03-05 22:03:07 【问题描述】:

如果我有一个类似这样的轮胎表的 Postgresql 数据库模式(用户有很多轮胎):

user_id integer
description text
size integer
color text
created_at timestamp

我想强制执行“用户只能有 4 个轮胎”的约束。

实现这一点的一种天真的方法是:

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

,将结果与 4 进行比较,如果它低于 4,则插入。这可能是竞争条件,因此是一种幼稚的方法。

我不想添加计数列。我怎样才能使用排除约束来做到这一点(或者我可以做到这一点)?如果排除约束不可能,那么规范的方法是什么?

【问题讨论】:

【参考方案1】:

“正确”的方式是在这里使用锁。 首先,您需要锁定相关行。其次,如果用户的轮胎少于 4 个,则插入新记录。这是 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;

您可以在这里阅读更多内容How to perform conditional insert based on row count?

【讨论】:

你写的东西里潜伏着一个正确的答案。 SELECT ... FOR UPDATE 应该在user_id 上,并且INSERT 中的重新检查是不必要的。

以上是关于使用 Postgres 排除约束限制匹配特定条件的表行数?的主要内容,如果未能解决你的问题,请参考以下文章

冲突部分索引的 Postgres 唯一或排除约束无法更新票证

Postgres 忽略表约束,即使约束不匹配也会扫描所有继承的表

没有选择的Postgres条件唯一约束

如何使用 ConstraintMapping 排除码头中的特定路径?

如何处理具有排除约束的表的更新?

在 postgres 中匹配 regexp_replace 中的 2 个条件