0

我有一个夜间存档工作,将现有行从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 _rrecords_archive不仅因为我很懒,而且因为这个存储过程将成为这些表中任何未来列更改的依赖项。

我遇到的问题是这在语法或概念上不起作用:

INSERT INTO records_archive VALUES (_r.*);

这些都不行:

INSERT INTO records_archive _r;
INSERT INTO records_archive _r.*;

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

4

1 回答 1

1

我会在records_archive. 对 NEW.master_guid进行选择records_archive,如果存在,请对其进行操作以添加随机数。

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

于 2013-11-01T14:42:22.353 回答