我有一个夜间存档工作,将现有行从records
表中扫描到records_archive
:
INSERT INTO records_archive
SELECT * FROM records WHERE id > 555 AND id <= 556;
出于此问题范围之外的原因,master_guid
两者都有一列 -- --records
并且records_archive
有一个UNIQUE
索引,我无法更改它。由于我无法控制的原因,将索引重建为非唯一索引是不可能的。因此,原则上,每个master_guid
值都应该是唯一的。但是,有一些糟糕的客户端实现有时无法生成足够唯一的 GUID,当我们尝试将记录插入records_archive
到具有master_guid
已存在于records_archive
.
我无法修复客户端,所以我需要解决它。这样做的方法是捕获unique_violation
异常,修改 GUID(向其中添加一些随机字符),然后尝试重新插入。
我不能只将上述INSERT
查询包装在存储过程中并捕获unique_violation
异常,因为整个查询是一个事务。我需要行级访问。因此,我编写了一个存储过程来遍历每一行并分别捕获unique_violation
该行的异常:
CREATE OR REPLACE FUNCTION archive_records(start_id bigint,
end_id bigint)
RETURNS void
AS $$
DECLARE
_r record;
BEGIN
FOR _r IN
SELECT * FROM records WHERE id > start_id AND id <= end_id
LOOP
BEGIN
INSERT INTO records_archive VALUES (_r.*);
EXCEPTION WHEN unique_violation THEN
-- Manipulate the _r.master_guid value, add some random
-- numbers to it or whatever, and attempt reinsertion.
END;
END LOOP;
END;
$$ LANGUAGE 'plpgsql';
问题是records
(and records_archive
) 是非常宽的表格。我不想显式枚举要从中复制的每一列 to _r
,records_archive
不仅因为我很懒,而且因为这个存储过程将成为这些表中任何未来列更改的依赖项。
我遇到的问题是这在语法或概念上不起作用:
INSERT INTO records_archive VALUES (_r.*);
这些都不行:
INSERT INTO records_archive _r;
INSERT INTO records_archive _r.*;
有没有办法解决这个问题?如果没有,有没有更好的方法来完成我想要完成的事情?