我目前保留一个CSV主文件,我经常更新以管理产品列表。
如果我尝试直接导入CSV文件,我会收到错误“重复键值违反唯一约束...”目前,我通过删除表中的所有项目来更新我的Products Postgres表并导入所有数据再次。
我意识到这不是一个很好的方法。有没有更好的方法来解决这个问题?我目前使用pgAdmin III和PG Commander客户端。
答案 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文件中不存在的任何记录。如果你希望它能够工作,你需要一个更复杂的解决方案 - 也许是这样的序列:
删除真实表中temp中不存在的所有行。表
DELETE FROM test WHERE id NOT IN (SELECT id FROM temp);
然后最后从temp中插入行。表进入真实表:
INSERT INTO test(id,name,amount) (SELECT id,name,amount FROM temp);
如果表可能会被其他用户同时更新,则此答案不会考虑并发问题。但是,如果您只是从CSV文件加载if,那么这可能不是问题。