You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PostgreSQL导入CSV文件时如何仅写入主键唯一的新增行

PostgreSQL导入CSV自动跳过主键重复行实现方案

前置依赖

首先必须确保存储日报数据的正式表,已经给主键id字段创建了主键约束或唯一约束,这是数据库判断重复的核心依据,没有约束所有去重逻辑都无法生效。
参考建表语句:

CREATE TABLE IF NOT EXISTS daily_report (
    id INTEGER PRIMARY KEY, -- 主键字段,类型根据实际业务调整,支持BIGINT、VARCHAR等类型
    -- 下方按CSV实际列添加字段即可,例如report_date DATE, trade_amount NUMERIC, remark TEXT
    col1 VARCHAR,
    col2 INTEGER,
    create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

通用兼容方案(支持所有PostgreSQL版本)

通过临时表中转导入,再做增量插入,不会残留垃圾数据,逻辑可控:

  • 创建和正式表结构完全一致的临时表,临时表仅当前会话可见,会话断开后自动删除:
CREATE TEMP TABLE temp_daily_report (LIKE daily_report INCLUDING ALL);
  • 将CSV文件导入临时表,根据自己的文件实际情况调整参数:
COPY temp_daily_report(id, col1, col2) -- 字段顺序必须和CSV内列顺序完全对应
FROM '/your/local/path/daily_report.csv' -- 替换为你的CSV文件绝对路径
WITH (
    FORMAT csv,
    HEADER true, -- CSV第一行是列名表头填true,无表头填false
    ENCODING 'UTF8' -- 按CSV实际编码调整,Windows导出的文件通常填GBK
);

如果是用psql客户端操作本地文件,把COPY换成\copy即可,避免服务端文件权限问题。

  • 执行增量插入,仅写入正式表不存在的id对应行:
INSERT INTO daily_report (id, col1, col2)
SELECT id, col1, col2
FROM temp_daily_report
WHERE NOT EXISTS (
    SELECT 1 FROM daily_report WHERE daily_report.id = temp_daily_report.id
);

执行完成后提交事务即可,不需要手动清理临时表。

简化写法(PostgreSQL 9.5及以上版本支持)

9.5之后版本原生支持冲突跳过语法,性能更好,写法更简洁,只需要把上述第三步的插入语句替换成下面的内容即可:

INSERT INTO daily_report (id, col1, col2)
SELECT id, col1, col2 FROM temp_daily_report
ON CONFLICT (id) DO NOTHING;

语句逻辑为:插入时如果碰到id字段冲突(也就是已存在相同id),直接跳过该行不做任何操作,不会报错也不会覆盖原有数据。

特殊情况处理

如果单份CSV文件内部本身就存在重复id的行,可以在插入时先对临时表数据按id去重,避免插入时报错:

INSERT INTO daily_report (id, col1, col2)
SELECT DISTINCT ON (id) id, col1, col2
FROM temp_daily_report
ON CONFLICT (id) DO NOTHING;

注意:不要直接用COPY命令往正式表导入CSV,一旦碰到重复主键,整个导入操作会直接报错回滚,无法自动跳过重复行。如果用DBeaver、pgAdmin这类可视化工具导入,逻辑完全一致,先把数据导入临时表,再执行增量插入语句即可。

内容的提问来源于stack exchange,提问作者CluelessDawg1337

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.03 04:01:18