每周收到同一份 CSV:用 SQLite 避免台账重复导入
先把 CSV 放入临时表,再按稳定编号合并。示例区分新增、更新与缺失记录,保留前导零,并避免把 REPLACE 当成普通更新。
文章目录
每周把供应商发来的 CSV 追加到台账,过几周就会出现同一个设备多行。直接清空重导,又可能丢掉你自己补的备注。适合这种场景的做法是先暂存文件,按稳定编号合并,把外部字段与本地字段分开。
先确定用哪一列识别同一条记录
设备名称会改,所在部门会变,文件里的行号也会重排。示例使用 asset_id 作为唯一编号,保留文本类型以免丢掉前导零。若来源根本没有稳定编号,需要先约定识别规则,不能拿名称相似就自动合并。
创建一个新的演示库;正式操作前另存现有台账备份。以下 CSV 保存为 assets.csv:
asset_id,name,department
0001,投影仪,会议室
0002,相机,设计组
进入 sqlite3 demo-assets.db,在 SQLite 命令行中执行:
CREATE TABLE assets (
asset_id TEXT PRIMARY KEY NOT NULL,
name TEXT NOT NULL,
department TEXT,
local_note TEXT
);
CREATE TEMP TABLE incoming (
asset_id TEXT,
name TEXT,
department TEXT
);
再用命令行的点命令导入。下面的写法需要支持 --skip 的 sqlite3 CLI:
.mode csv
.import --skip 1 assets.csv incoming
--skip 1 跳过表头。先建暂存表,再导入,能够明确列数与类型;不能把错列文件直接塞进正式表。
合并前先查异常
SELECT asset_id, COUNT(*)
FROM incoming GROUP BY asset_id HAVING COUNT(*) > 1;
SELECT * FROM incoming
WHERE asset_id IS NULL OR trim(asset_id) = ''
OR name IS NULL OR trim(name) = '';
第一条找到同一批文件中的重复编号,第二条找必填空值。出现异常时先处理文件,不要让“最后一行覆盖前一行”变成未经约定的规则。也要核对导入行数和几个原始编号。
只更新外部负责的字段
SQLite 3.24.0 起支持 UPSERT。异常处理完成后:
BEGIN;
INSERT INTO assets (asset_id, name, department)
SELECT asset_id, name, department
FROM incoming WHERE true
ON CONFLICT(asset_id) DO UPDATE SET
name = excluded.name,
department = excluded.department;
COMMIT;
WHERE true 用于消除这类 INSERT ... SELECT ... ON CONFLICT 的解析歧义。冲突时更新名称和部门,没有写入 local_note,本地备注就不会被这份外部 CSV 覆盖。INSERT OR REPLACE 可能删除冲突行再插入,涉及关联或触发器时与普通更新不同,不要混用。
来源文件里缺少某个编号,并不自动表示设备已经报废;它可能只是导出了某个部门。示例不会删除这些记录。只有明确约定“全量清单”及缺失处理方式后,才另做停用或删除流程。
把导入日期、文件名、行数和异常处理记在旁边。下一次更新前清空或重建暂存表,避免把两批输入混在一起。点命令详见 SQLite CLI 文档,合并行为见 UPSERT 说明。