更新期间唯一索引违规

时间:2017-06-02 09:48:12

标签: postgresql

我在更大的数据库中遇到了唯一的索引违规。原始问题发生在存储的pl / pgsql函数中。

我简化了一切以显示我的问题。我可以在一个相当简单的表格中重现它:

CREATE TABLE public.test
(
  id integer NOT NULL DEFAULT nextval('test_id_seq'::regclass),
  pos integer,
  text text,
  CONSTRAINT text_pkey PRIMARY KEY (id)
)
WITH (
  OIDS=FALSE
);

ALTER TABLE public.test
  OWNER TO root;
GRANT ALL ON TABLE public.test TO root;

我在' pos':

上定义了一个唯一索引
CREATE UNIQUE INDEX test_idx_pos
  ON public.test
  USING btree
  (pos);

在UPDATE之前,表格中的数据如下所示:

testdb=# SELECT * FROM test;
 id | pos |   text   
----+-----+----------
  2 |   1 | testpos1
  3 |   2 | testpos2
  1 |   5 | testpos4
  4 |   4 | testpos3
(4 Zeilen)
tr: (4 rows)

现在我想减少所有' pos'值大于2并且得到错误(tr是我从德语到英语的翻译):

testdb=# UPDATE test SET pos = pos - 1 WHERE pos > 2;
FEHLER:  doppelter Schlüsselwert verletzt Unique-Constraint »test_idx_pos«
tr: ERROR: duplicate key violates unique constraint »test_idx_pos«
DETAIL:  Schlüssel »(pos)=(4)« existiert bereits.
tr: key »(pos)=(4) already exists.

如果UPDATE运行完毕,表格将如下所示并再次成为唯一:

testdb=# SELECT * FROM test;
 id | pos |   text   
----+-----+----------
  2 |   1 | testpos1
  3 |   2 | testpos2
  1 |   4 | testpos4
  4 |   3 | testpos3
(4 Zeilen)
tr: (4 rows)

我该如何避免这种情况?我了解到存储的pl / pgsql函数嵌入到事务中,所以这个问题不应该出现?

1 个答案:

答案 0 :(得分:4)

每行评估唯一索引而不是每个语句(例如,与Oracle的实现不同)

此问题的解决方案是使用唯一的约束,它可以延迟,因此在事务结束时进行评估。

如此而不是唯一索引,定义一个约束:

alter table test add constraint test_idx_pos unique (pos)
  deferrable initially deferred;