我希望在Postgres 10中有一个SQL语句或函数,只有在行数少于一定数量的情况下才允许我插入一行。
select count(*) from mytable where mykey = 1
--- do the following only if the above is less than 5
insert into mytable (myvalue, mykey) values ('randomvalue', 1)
--- so there are never more than 5 rows in mytable with mykey = 1
像这个伪代码这样的东西会起作用吗(对postgres服务器的多次往返调用)?
tx = app.tx("start transaction");
count = tx.query("select count(*) from mytable where mykey = 1")
if (count < 5) {
tx.query("insert into mytable (myvalue, mykey) values ('randomvalue', 1)")
}
tx.do("commit")
如果它不起作用,我怎么能在Postgres方面这样做,所以我只从应用程序拨打一个电话,如select myinsertfunction('randomvalue', 1)
?
无论是上面这样做的多次往返方式,还是对postgres的单次调用,最重要的是没有办法以插入超过5行的方式并行运行。例如,事务1和2都检查计数是4(小于最大值5),并同时进行,因此它们最终将插入1行,每行总共6行而不是最多5个。
答案 0 :(得分:4)
问题称为Phantom Read:
事务重新执行一个查询,返回满足搜索条件的一组行,并发现满足条件的行集由于另一个最近提交的事务而发生了更改。
尝试
BEGIN;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
INSERT INTO mytable (myvalue, mykey) SELECT 'randomvalue', 1 WHERE
(SELECT COUNT(*) FROM mytable WHERE mykey = 1) < 5;
END;
事务隔离级别将确保事务仅在计数小于5时插入值。