将 CSV 导入 Postgres 并根据需要更新/替换任何字段
Posted
技术标签:
【中文标题】将 CSV 导入 Postgres 并根据需要更新/替换任何字段【英文标题】:Import CSV into Postgres and update/replace any fields if need so 【发布时间】:2014-04-02 05:59:34 【问题描述】:我目前保留一个 CSV 主文件,我经常在其中更新以管理产品列表。
如果我尝试直接导入 CSV 文件,我会收到错误“重复键值违反唯一约束...”目前,我通过删除表中的所有项目并导入所有数据来更新我的 Products Postgres 表再次进入。
我意识到这不是一个很好的方法。有没有更好的方法来解决这个问题?我目前使用 pgAdmin III 和 PG Commander 客户端。
【问题讨论】:
出于好奇,为什么 CSV 是主文件? @leigh 对非技术人员来说更容易管理吗? 如果 CSV 真的 是信息的主要来源,则截断/导入是最快的方法。您可以考虑使用外部数据包装器直接访问文件,但对于大型查询可能不会很快。 【参考方案1】:您可以通过定义一个尝试更新现有记录的触发器函数来做到这一点,并且只有在没有找到记录时才允许插入。
为此,您当然需要有一个主键或其他标准来唯一标识行。
假设你的表是这样定义的:
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 文件中不存在的任何记录。如果你想让它起作用,你需要一个更复杂的解决方案——也许是这样的序列:
-
将 CSV 文件加载到临时表中
从实际表中删除临时表中不存在的所有行。表
DELETE FROM test WHERE id NOT IN (SELECT id FROM temp);
然后最后从临时插入行。表变成真实表:
INSERT INTO test(id,name,amount) (SELECT id,name,amount FROM temp);
此答案不考虑并发问题,以防其他用户同时更新表。但是,如果您只从 CSV 文件中加载,那么这不太可能成为问题。
【讨论】:
确实没有相当于 mysqlINSERT ON DUPLICATE
的 postgres ?!?
@FrankN 写这个答案时没有,但现在有。请参阅:postgresql.org/docs/current/static/sql-insert.html。但是,对于原始问题没有帮助,这与从 CSV 文件加载数据有关,而不是使用 INSERT 语句。以上是关于将 CSV 导入 Postgres 并根据需要更新/替换任何字段的主要内容,如果未能解决你的问题,请参考以下文章
SQL 中有没有办法将目录中包含的所有 .csv 导入我的 postgres 表? (窗口操作系统)
如何使用 Postgres 中 CSV 文件中的值更新选定的行?