Postgresql EXCLUDE 约束在 INSERT 时不触发 ON CONFLICT
Postgresql EXCLUDE constraint not triggering ON CONFLICT when INSERT
我已经定义了这个table:
CREATE TABLE market.price_history (
item_id bigint NOT NULL,
valid_time tstzrange DEFAULT tstzrange(now(), 'infinity'),
sale_price money NOT NULL,
promo_code bool NOT NULL DEFAULT false,
EXCLUDE USING gist(item_id WITH =, valid_time WITH &&),
EXCLUDE USING gist(item_id WITH =, sale_price WITH =, valid_time WITH &&)
);
但是当我这样做时SQL:
WITH new_row_valid_time as(
SELECT tstzrange(MAX(upper(valid_time)),
'infinity'::timestamptz) as adjacent_valid_time
FROM market.price_history
WHERE item_id = 11
)
INSERT INTO market.price_history as ph
(item_id, valid_time, sale_price, promo_code)
VALUES(11, -- same id as existent row
(SELECT adjacent_valid_time
FROM new_row_valid_time), -- adjacent range for existent row
11.83, -- same price as the existent row
False)
ON CONFLICT (item_id, sale_price, valid_time) DO
UPDATE SET valid_time = tstzrange(lower(ph.valid_time), 'infinity'::timestamptz)
WHERE ph.item_id = excluded.item_id
AND ph.sale_price = excluded.sale_price
AND upper(ph.valid_time) = lower(excluded.valid_time);
我希望执行 ON CONFLICT
子句,因为要插入的行具有相同的 item_id
、sale_price
和 valid_time
与现有的相邻。相反,我得到这个:
ERROR: there is no unique or exclusion constraint matching the ON CONFLICT specification
我是不是误会了什么?我相信第二个 EXCLUDE
子句中的排除约束涉及相同的 3 列。我正在搜索文档,但 ON CONFLICT
说明对我来说不是很清楚。
The documentation 有点简洁的评论:
Note that exclusion constraints are not supported as arbiters with ON CONFLICT DO UPDATE
.
查看源代码使情况更清楚:
您永远不能对 ON CONFLICT DO UPDATE
使用排除约束。
不过,您可以使用
ON CONFLICT ON CONSTRAINT price_history_item_id_valid_time_excl DO NOTHING
也就是说,您可以使用带 DO NOTHING
的命名排除约束。
没有排除约束的“约束推断”,即,即使在DO NOTHING
情况下,您也不能仅在括号中指定索引表达式并让 PostgreSQL 找到相应的排除约束。
我已经定义了这个table:
CREATE TABLE market.price_history (
item_id bigint NOT NULL,
valid_time tstzrange DEFAULT tstzrange(now(), 'infinity'),
sale_price money NOT NULL,
promo_code bool NOT NULL DEFAULT false,
EXCLUDE USING gist(item_id WITH =, valid_time WITH &&),
EXCLUDE USING gist(item_id WITH =, sale_price WITH =, valid_time WITH &&)
);
但是当我这样做时SQL:
WITH new_row_valid_time as(
SELECT tstzrange(MAX(upper(valid_time)),
'infinity'::timestamptz) as adjacent_valid_time
FROM market.price_history
WHERE item_id = 11
)
INSERT INTO market.price_history as ph
(item_id, valid_time, sale_price, promo_code)
VALUES(11, -- same id as existent row
(SELECT adjacent_valid_time
FROM new_row_valid_time), -- adjacent range for existent row
11.83, -- same price as the existent row
False)
ON CONFLICT (item_id, sale_price, valid_time) DO
UPDATE SET valid_time = tstzrange(lower(ph.valid_time), 'infinity'::timestamptz)
WHERE ph.item_id = excluded.item_id
AND ph.sale_price = excluded.sale_price
AND upper(ph.valid_time) = lower(excluded.valid_time);
我希望执行 ON CONFLICT
子句,因为要插入的行具有相同的 item_id
、sale_price
和 valid_time
与现有的相邻。相反,我得到这个:
ERROR: there is no unique or exclusion constraint matching the ON CONFLICT specification
我是不是误会了什么?我相信第二个 EXCLUDE
子句中的排除约束涉及相同的 3 列。我正在搜索文档,但 ON CONFLICT
说明对我来说不是很清楚。
The documentation 有点简洁的评论:
Note that exclusion constraints are not supported as arbiters with
ON CONFLICT DO UPDATE
.
查看源代码使情况更清楚:
您永远不能对
ON CONFLICT DO UPDATE
使用排除约束。不过,您可以使用
ON CONFLICT ON CONSTRAINT price_history_item_id_valid_time_excl DO NOTHING
也就是说,您可以使用带
DO NOTHING
的命名排除约束。没有排除约束的“约束推断”,即,即使在
DO NOTHING
情况下,您也不能仅在括号中指定索引表达式并让 PostgreSQL 找到相应的排除约束。