Postgres版本化的行

时间:2019-02-26 21:40:42

标签: sql postgresql

我想在Postgres的行级中保留版本

 Column   |           Type           |            Modifiers
------------+--------------------------+----------------------------------
id         | integer                  | not null
version    | integer                  | not null default 0
Indexes:
    "mytable_pk" PRIMARY KEY, btree (id, version)

我打算使用版本0作为当前版本。

一个例子:

最初:

INSERT INTO mytable(id, version) VALUES(1, 0);

然后

UPDATE mytable SET version = version + 1 where id = 1;
INSERT INTO mytable(id, version) VALUES(1, 0);

然后

UPDATE mytable SET version = version +1 where id = 1;

出现错误

ERROR:  duplicate key value violates unique constraint "mytable_pk"
DETAIL:  Key (id, version)=(1, 1) already exists.

我在Mysql中使用此模式没有问题。 关于如何在Postgres中实现上述目标的任何提示?

3 个答案:

答案 0 :(得分:2)

这是一个已知问题,在某些数据库中具有唯一约束。这是一种解决方法:

UPDATE mytable
    SET version = - (version + 1)
    WHERE id = 1;

UPDATE mytable
    SET version = - version
    WHERE id = 1 AND version < 0;

您也许还可以使用ORDER BY来解决此问题:

UPDATE mytable
    SET version = version + 1 
    WHERE id = 1
    ORDER BY version DESC;

答案 1 :(得分:1)

默认情况下,唯一约束被“逐行”验证,这就是为什么会出现该错误的原因,但是如果您将其定义为可延迟的,则可以更改每个语句要验证的约束:

alter table mytable
  add constraint pk_mytable primary key (id, version) 
  deferrable initially immediate;

该解决方案的缺点是,该主键不再是外键的目标。

答案 2 :(得分:0)

postgresql的版本是什么?我在9.5上进行了测试,一切正常。

    postgres=# select version();
                                                      version
-------------------------------------------------------------------------------------------------------------------
 PostgreSQL 9.5.14 on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 5.4.0-6ubuntu1~16.04.10) 5.4.0 20160609, 64-bit
(1 row)

postgres=# \d mytable
          Table "public.mytable"
 Column  |  Type   |     Modifiers
---------+---------+--------------------
 id      | integer | not null
 version | integer | not null default 0
Indexes:
    "mytable_pkey" PRIMARY KEY, btree (id, version)

postgres=# INSERT INTO mytable(id, version) VALUES(1, 0);
INSERT 0 1
postgres=# UPDATE mytable SET version = version + 1 where id = 1;
UPDATE 1
postgres=# INSERT INTO mytable(id, version) VALUES(1, 0);
INSERT 0 1
postgres=# UPDATE mytable SET version = version +1 where id = 1;
UPDATE 2
postgres=# select * from mytable ;
 id | version
----+---------
  1 |       2
  1 |       1
(2 rows)