如果需要,将CSV导入Postgres并更新/替换任何字段

时间:2014-04-02 05:59:35

标签: postgresql csv postgresql-9.2

我目前保留一个CSV主文件,我经常更新以管理产品列表。

如果我尝试直接导入CSV文件,我会收到错误“重复键值违反唯一约束...”目前,我通过删除表中的所有项目来更新我的Products Postgres表并导入所有数据再次。

我意识到这不是一个很好的方法。有没有更好的方法来解决这个问题?我目前使用pgAdmin III和PG Commander客户端。

1 个答案:

答案 0 :(得分:3)

您可以通过定义触发器功能来尝试更新现有记录,并且只有在找不到任何记录时才允许插入。

要使其正常工作,您需要拥有主键或其他标准来唯一标识行。

假设您的表定义如下:

CREATE TABLE TEST(
  id INT PRIMARY KEY, 
  name TEXT, 
  amount INT
);

触发器功能可能如下所示:

CREATE OR REPLACE FUNCTION test_insert_before_func()
RETURNS TRIGGER
 AS $BODY$
DECLARE
    exists INTEGER; 
BEGIN

    UPDATE test SET name=new.name, amount=new.amount
    WHERE id=new.id
    RETURNING id INTO exists;

    -- If the above was successful, it would return non-null
    -- in that case we return NULL so that the triggered INSERT
    -- does not proceed
    IF exists is not null THEN
        RETURN NULL;
    END IF;

    -- Otherwise, return the new record so that triggered INSERT
    -- goes ahead
    RETURN new;


END; 
$BODY$
LANGUAGE 'plpgsql' SECURITY DEFINER;

CREATE TRIGGER test_insert_before_trigger
   BEFORE INSERT
   ON test
   FOR EACH ROW
   EXECUTE PROCEDURE test_insert_before_func();

现在,如果我插入一个尚不存在的行,则会插入:

test=> insert into test(id,name,amount) values (1,'Mary',100);
INSERT 0 1
test=> select * from test;
 id | name | amount
----+------+--------
  1 | Mary |    100
(1 row)

如果我尝试插入具有相同ID的行:

test=> insert into test(id,name,amount) values (1,'Mary',200);
INSERT 0 0
test=> select * from test;
 id | name | amount
----+------+--------
  1 | Mary |    200
(1 row)

这次更新行而不是插入。

如果我从CSV文件加载行,它也可以正常工作。

但是:您可能没有考虑过一件事:这不会删除数据库中存在且CSV文件中不存在的任何记录。如果你希望它能够工作,你需要一个更复杂的解决方案 - 也许是这样的序列:

  1. 将CSV文件加载到临时表中
  2. 删除真实表中temp中不存在的所有行。表

    DELETE FROM test WHERE id NOT IN (SELECT id FROM temp);
    
  3. 然后最后从temp中插入行。表进入真实表:

    INSERT INTO test(id,name,amount) (SELECT id,name,amount FROM temp);
    
  4. 如果表可能会被其他用户同时更新,则此答案不会考虑并发问题。但是,如果您只是从CSV文件加载if,那么这可能不是问题。