这更像是一个概念性问题,因为我正在计划如何最好地实现我们的目标。
我有一个包含5列的postgresql / postgis表。我将通过copy命令每隔10分钟左右从csv文件插入/附加数据到数据库。可能会有一些重复的数据行,所以我想将数据从csv文件复制到postgresql表,但是防止任何重复的条目从csv文件进入表。有三列,如果它们全部相等,则表示该条目是重复的。它们是“纬度”,“经度”和“时间”。我应该从所有三列制作复合键吗?如果我这样做,它会在尝试将csv文件复制到数据库时抛出错误吗?我将自动复制csv文件,所以我希望它继续并复制不重复的文件的其余部分,而不是复制重复项。有没有办法做到这一点?
此外,我当然希望它以最有效的方式查找重复项。我不需要查看整个表(这将是非常大的)重复...只是通过行上的时间戳过去20分钟左右。我用时间列索引了数据库。
感谢您的帮助!
答案 0 :(得分:3)
我想我会采取以下方法。
首先,在您关心的三列上创建一个索引:
create unique index idx_bigtable_col1_col2_col3 on bigtable(col1, col2, col3);
然后,使用copy
将数据加载到临时表中。最后,你可以这样做:
insert into bigtable(col1, . . . )
select col1, . . .
from stagingtable st
where (col1, col2, col3) not in (select col1, col2, col3 from bigtable);
假设没有其他数据修改,这应该可以实现您想要的。从性能角度来看,使用索引检查重复项应该没问题。
另一种方法是在重复密钥更新"上模拟MySQL"忽略这些记录。 Bill Karwin建议在回答question时实施一条规则。规则的文档是here。使用触发器也可以做类似的事情。
答案 1 :(得分:2)
Answer by Linoff是正确的,但可以简化Postgres 9.5 new ”UPSERT“ feature(a.k.a。MERGE
)。该新功能在Postgres中以INSERT ON CONFLICT
语法实现。
我们可以让ON CONFLICT
子句检测违规,而不是显式检查是否违反了唯一索引。然后我们DO NOTHING
,这意味着我们放弃了INSERT
的努力,而没有费心去尝试UPDATE
。因此,如果我们无法插入,我们只需转到下一行。
我们得到的结果与Linoff的代码相同但却失去了WHERE
条款。
INSERT INTO bigtable(col1, … )
SELECT col1, …
FROM stagingtable st
ON CONFLICT idx_bigtable_col1_col2_col
DO NOTHING
;
答案 2 :(得分:2)
Basil的方法很棒,但是有轻微的语法错误。我不确定为什么@Bhargav Rao删除了我以前的帖子。通过某种方式参考文档https://www.postgresql.org/docs/9.5/sql-insert.html,我可以使其正常工作。
INSERT INTO bigtable(col1, … )
SELECT col1, …
FROM stagingtable st
ON CONFLICT (col1)
DO NOTHING
;