当重复记录已存在时,改变 Postgres table 以具有唯一约束
Altering Postgres table to have unique with constraint when duplicates records alredy exist
我们正在使用由 Postgres 支持的 Django ORM。
我们有一些 table ("foo") 有重复的记录,我们想要改变并添加一些唯一的约束,这样就不会插入重复。
为了做到这一点,我们首先需要删除重复的记录,然后添加唯一约束(否则使用alter table添加约束会因为记录重复而失败)。
我想运行以下事务以实现上述流程-
BEGIN WORK;
DELETE FROM foo
WHERE id IN
(SELECT id
FROM
(SELECT id,
ROW_NUMBER() OVER( PARTITION BY a1, a2
ORDER BY id ) AS row_num
FROM foo ) t
WHERE t.row_num > 1 );
LOCK TABLE foo IN SHARE ROW EXCLUSIVE MODE;
DELETE FROM foo
WHERE id IN
(SELECT id
FROM
(SELECT id,
ROW_NUMBER() OVER( PARTITION BY a1, a2
ORDER BY id ) AS row_num
FROM foo ) t
WHERE t.row_num > 1 );
ALTER TABLE "foo" ADD CONSTRAINT "some_constaint_name" UNIQUE ("a1", "a2");
COMMIT WORK;
- 删除部分在这里两次,以尽量减少获取锁的时间
- 加锁是为了阻止在delete和alter语句之间进行更多的重复插入。
但是,这失败了
“不能改变 TABLE “foo”,因为它有未决的触发事件”,我想这是有道理的。
如果是这样,我该怎么做才能达到我想要的独特性?
由于 table 具有的数据量,无法将数据复制到新的 table...
我看不出锁或两个删除语句的目的,但要立即执行触发器,运行 在 ALTER TABLE
:
之前
SET CONSTRAINTS ALL IMMEDIATE;
我们正在使用由 Postgres 支持的 Django ORM。
我们有一些 table ("foo") 有重复的记录,我们想要改变并添加一些唯一的约束,这样就不会插入重复。
为了做到这一点,我们首先需要删除重复的记录,然后添加唯一约束(否则使用alter table添加约束会因为记录重复而失败)。
我想运行以下事务以实现上述流程-
BEGIN WORK;
DELETE FROM foo
WHERE id IN
(SELECT id
FROM
(SELECT id,
ROW_NUMBER() OVER( PARTITION BY a1, a2
ORDER BY id ) AS row_num
FROM foo ) t
WHERE t.row_num > 1 );
LOCK TABLE foo IN SHARE ROW EXCLUSIVE MODE;
DELETE FROM foo
WHERE id IN
(SELECT id
FROM
(SELECT id,
ROW_NUMBER() OVER( PARTITION BY a1, a2
ORDER BY id ) AS row_num
FROM foo ) t
WHERE t.row_num > 1 );
ALTER TABLE "foo" ADD CONSTRAINT "some_constaint_name" UNIQUE ("a1", "a2");
COMMIT WORK;
- 删除部分在这里两次,以尽量减少获取锁的时间
- 加锁是为了阻止在delete和alter语句之间进行更多的重复插入。
但是,这失败了 “不能改变 TABLE “foo”,因为它有未决的触发事件”,我想这是有道理的。
如果是这样,我该怎么做才能达到我想要的独特性? 由于 table 具有的数据量,无法将数据复制到新的 table...
我看不出锁或两个删除语句的目的,但要立即执行触发器,运行 在 ALTER TABLE
:
SET CONSTRAINTS ALL IMMEDIATE;