在Postgresql中执行upsert时,在ON CONFLICT子句中未使用部分索引

时间:2017-10-13 10:24:43

标签: postgresql indexing unique upsert partial-index

我有以下实体属性值表:

CREATE TABLE key_value_pair (
    id serial NOT NULL PRIMARY KEY,
    key varchar(255) NOT NULL,
    value varchar(255),
    is_active boolean
);

CREATE UNIQUE INDEX key_value_pair_key_if_is_active_true_unique ON key_value_pair (key) WHERE is_active = true;

此表中的示例条目为:

id |     key     | value | is_active 
----+-------------+-------+-----------
  1 | temperature | 2     | f
  2 | temperature | 12    | f
  3 | temperature | 15    | f
  4 | temperature | 19    | f
  5 | temperature | 23    | t
(5 rows)

因此,在任何时间点,对于任何给定的密钥,只应存在1个真正的is_active条目。

我在此表上运行以下upsert语句:

INSERT INTO key_value_pair (key, value, is_active) VALUES ('temperature','20', true) 
ON CONFLICT (key, is_active)
DO UPDATE
SET value = '33', is_active = true;

但是,它失败了:

ERROR:  there is no unique or exclusion constraint matching the ON CONFLICT specification

我想知道为什么它没有使用唯一的部分索引 key_value_pair_key_if_is_active_true_unique

如果我在任何时间点放开“,对于任何给定的密钥,只有1个真正的is_active条目应该存在”子句并且将索引更改为:

CREATE UNIQUE INDEX key_value_pair_key_if_is_active_true_unique ON key_value_pair (key, is_active);

我在Postgres网站上阅读了有关ON CONFLICT子句将使用部分索引的文档。我想知道为什么在这种情况下不使用它。我在这里错过了什么,或者我犯了什么错误?

2 个答案:

答案 0 :(得分:9)

您必须使用索引谓词来使用部分唯一索引。请阅读the documentation:

  

index_predicate

     

用于允许推断部分唯一索引。可以推断出满足谓词的任何索引(实际上不需要是部分索引)。遵循CREATE INDEX格式。

在这种情况下:

INSERT INTO key_value_pair (key, value, is_active) VALUES ('temperature','20', false) 
ON CONFLICT (key) WHERE is_active
DO UPDATE
SET value = '33', is_active = true;

答案 1 :(得分:0)

另一个例子:

> users
id | name   | colour
---+--------+-------
1  | 'greg' | 'blue'

--------------------------------------------------------------------------
CREATE UNIQUE INDEX index_name
  --columns applicable to partial index
  ON users (id, name)
  --partial index condition   **
  WHERE id = 1;

--------------------------------------------------------------------------
INSERT INTO users (id, name, colour)
    --multiple inserts
VALUES (1, 'george', 'blue'),
       (2, 'pieter', 'brown'),
       (3, 'kobus', 'pink')
ON CONFLICT (id, name)
    --partial index condition  **same as original partial index condition
  WHERE id = 1
    --conflict action
  DO UPDATE SET
        name = EXCLUDED.name;

现在id = 1的行将更新为name = george,其余的将被创建