在 Postgresql 中执行更新插入时,ON CONFLICT 子句中未使用部分索引
Partial Index not used in ON CONFLICT clause while performing an upsert in Postgresql
我有以下实体属性值 table :
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;
此 table 中的示例条目是:
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 条目。
我是 运行 关于此 table 的以下更新插入语句:
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 子句使用的文档。我想知道为什么在这种情况下不使用它。我在这里遗漏了什么,或者我犯了什么错误?
您必须使用索引谓词才能使用部分唯一索引。读入 the documentation:
index_predicate
Used to allow inference of partial unique indexes. Any indexes that satisfy the predicate (which need not actually be partial indexes) can be inferred. Follows CREATE INDEX format.
在这种情况下:
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;
另一个例子:
> users
id | name | colour | active
---+---------+----------+--------
1 | 'greg' | 'blue' | false
2 | 'kobus' | 'pink' | true
--------------------------------------------------------------------------
CREATE UNIQUE INDEX index_name
--columns applicable to partial index
ON users (name, colour)
--partial index condition **
WHERE not active
--------------------------------------------------------------------------
INSERT INTO users (name, colour, active)
--multiple inserts
VALUES ('greg', 'blue', false), --this already exists for [false], conflict
('pieter', 'blue', true),
('kobus', 'pink', false) --this already exists for [true], no conflict
ON CONFLICT (name, colour)
--partial index condition **same as original partial index condition
WHERE not active
--conflict action
DO UPDATE SET
active = not EXCLUDED.active
--on conflict example, change some value, i.e. update [active]
active = false
的 name = greg
和 colour = blue
行现在将更新为 active = true
,其余行将被插入
我有以下实体属性值 table :
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;
此 table 中的示例条目是:
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 条目。
我是 运行 关于此 table 的以下更新插入语句:
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 子句使用的文档。我想知道为什么在这种情况下不使用它。我在这里遗漏了什么,或者我犯了什么错误?
您必须使用索引谓词才能使用部分唯一索引。读入 the documentation:
index_predicate
Used to allow inference of partial unique indexes. Any indexes that satisfy the predicate (which need not actually be partial indexes) can be inferred. Follows CREATE INDEX format.
在这种情况下:
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;
另一个例子:
> users
id | name | colour | active
---+---------+----------+--------
1 | 'greg' | 'blue' | false
2 | 'kobus' | 'pink' | true
--------------------------------------------------------------------------
CREATE UNIQUE INDEX index_name
--columns applicable to partial index
ON users (name, colour)
--partial index condition **
WHERE not active
--------------------------------------------------------------------------
INSERT INTO users (name, colour, active)
--multiple inserts
VALUES ('greg', 'blue', false), --this already exists for [false], conflict
('pieter', 'blue', true),
('kobus', 'pink', false) --this already exists for [true], no conflict
ON CONFLICT (name, colour)
--partial index condition **same as original partial index condition
WHERE not active
--conflict action
DO UPDATE SET
active = not EXCLUDED.active
--on conflict example, change some value, i.e. update [active]
active = false
的 name = greg
和 colour = blue
行现在将更新为 active = true
,其余行将被插入