我有一个夜间存档作业,将records
表中的现有行扫描到records_archive
:
INSERT INTO records_archive
SELECT * FROM records WHERE id > 555 AND id <= 556;
由于超出此问题范围的原因,master_guid
和records
中的列{ - {1}}都有records_archive
索引,我无法改变这一点。由于我无法控制的原因,将索引重建为非唯一索引。因此,原则上,每个UNIQUE
值都应该是唯一的。有一些糟糕的客户端实现有时无法生成足够多的唯一GUID,当我们尝试将记录插入到master_guid
中且已存在records_archive
值的记录时会导致冲突master_guid
。
我无法修复客户端,所以我需要解决它。这样做的方法是捕获records_archive
异常,修改GUID(向其添加一些随机字符),并尝试重新插入。
我不能只在存储过程中包装上面提到的unique_violation
查询并捕获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
)是非常宽泛的表格。我不想显式枚举要从records_archive
复制到_r
的每一列,不仅因为我很懒,而且因为这个存储过程将成为以后任何列更改的依赖关系。那些表。
我遇到的问题是,这在语法或概念上都不起作用:
records_archive
这些都没有:
INSERT INTO records_archive VALUES (_r.*);
有没有办法解决这个问题?如果没有,是否有更好的方法来完成我想要完成的任务?
答案 0 :(得分:1)
我会在records_archive
上创建一个BEFORE INSERT触发器。在records_archive
上为NEW.master_guid做一个选择,如果存在,则操纵它来添加随机数。
您可能需要在检查周围进行循环,以确保在继续插入之前修改后的master_guid仍然不存在。