PL / PgSQL:捕获唯一的违规异常并从'record'变量中插入

时间:2013-11-01 14:22:09

标签: sql database postgresql plpgsql

我有一个夜间存档作业,将records表中的现有行扫描到records_archive

INSERT INTO records_archive 
    SELECT * FROM records WHERE id > 555 AND id <= 556;

由于超出此问题范围的原因,master_guidrecords中的列{ - {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.*);

有没有办法解决这个问题?如果没有,是否有更好的方法来完成我想要完成的任务?

1 个答案:

答案 0 :(得分:1)

我会在records_archive上创建一个BEFORE INSERT触发器。在records_archive上为NEW.master_guid做一个选择,如果存在,则操纵它来添加随机数。

您可能需要在检查周围进行循环,以确保在继续插入之前修改后的master_guid仍然不存在。