Pau*_*per 4 postgresql update unique-constraint
CREATE TABLE widget (
id serial PRIMARY KEY,
name text NOT NULL,
ordinal int NOT NULL UNIQUE
);
Run Code Online (Sandbox Code Playgroud)
我有数据
id | name | ordinal
----+------+---------
1 | A | 1
2 | B | 2
3 | C | 3
Run Code Online (Sandbox Code Playgroud)
我想将其更新为
id | name | ordinal
----+------+---------
1 | A | 3
2 | B | 2
3 | C | 1
Run Code Online (Sandbox Code Playgroud)
尽可能少地接触记录(即不要重写整个记录集,不要启动不必要的触发器),更新为ordinal
目标值的通用方法是什么?
普通更新只会给我带来约束违规,即使它发生在单个语句中。
删除并重新创建唯一约束的成本很高,而且并发性很差。
这似乎是一个很常见的问题,应该有一个好的方法来做到这一点,但我只是想不出。
小智 6
将约束定义为可延迟:
CREATE TABLE widget (
id serial PRIMARY KEY,
name text NOT NULL,
ordinal int NOT NULL UNIQUE DEFERRABLE
);
Run Code Online (Sandbox Code Playgroud)
然后你可以用一条语句更新它:
update widget
set ordinal = t.new_ordinal
from (
values (1, 3), (3,1)
) as t(id, new_ordinal)
where t.id = widget.id
Run Code Online (Sandbox Code Playgroud)
UNIQUE
默认情况下是简单约束NOT DEFERRABLE
。每行之后都会检查唯一的违规行为。该手册将其表述为:
每个命令后立即检查
但它确实检查了每个单独的书面行。
如果您定义了UNIQUE
约束(如提供的 a_horse),则在每个语句之后DEFERRABLE
都会检查唯一的违规行为。在这方面,同一查询中的多个 CTE 仍算作单个语句。
CREATE TABLE widget_deferrable (
id serial PRIMARY KEY,
ordinal int NOT NULL UNIQUE DEFERRABLE -- !
);
Run Code Online (Sandbox Code Playgroud)
如果您实际上也将约束设置为DEFERRED
,则对唯一违规的检查将推迟到每个事务之后。
CREATE TABLE widget_deferred (
id serial PRIMARY KEY,
ordinal int NOT NULL UNIQUE DEFERRABLE INITIALLY DEFERRED --!
);
Run Code Online (Sandbox Code Playgroud)
综合演示:
db<>在这里摆弄
进一步阅读:
归档时间: |
|
查看次数: |
1465 次 |
最近记录: |