为什么pandas的to_sql方法会生成重复数据?如何仅新增不重复条目?
解决方案
首先你当前使用if_exists='append'参数的to_sql方法本身就是全量追加逻辑,默认不会做重复数据校验,所以重复运行必然会导致数据重复写入,你可以通过以下两种方案实现仅新增不重复条目:
方案1:数据库层加唯一约束 + 自定义冲突处理(推荐)
这个方案是最稳妥的,从数据库底层避免重复数据写入,步骤如下:
- 首先给目标表的判重字段添加唯一约束,你可以提前在数据库执行DDL语句:
-- 此处col1/col2/col3替换为你判断一条数据是否重复的组合字段,比如业务ID、创建时间等 ALTER TABLE my_schema.my_table ADD CONSTRAINT unique_records UNIQUE (col1, col2, col3);
- 自定义
to_sql的插入方法,适配对应数据库的冲突忽略逻辑:
以PostgreSQL为例,定义插入方法后传入即可:
def insert_on_conflict_do_nothing(table, conn, keys, data_iter): from sqlalchemy.dialects.postgresql import insert data = [dict(zip(keys, row)) for row in data_iter] stmt = insert(table.table).values(data) stmt = stmt.on_conflict_do_nothing() result = conn.execute(stmt) return result.rowcount # 替换你原来的to_sql调用,替换method参数 df.to_sql('my_table', schema='my_schema', con=engine, if_exists='append', index=False, method=insert_on_conflict_do_nothing)
如果你用的是MySQL,把对应逻辑换成INSERT IGNORE的写法即可。
方案2:插入前手动过滤重复数据
如果暂时不方便修改数据库表结构,可以在插入前先拉取库表现有数据做对比,过滤掉重复条目后再写入:
import pandas as pd # 1. 先查询库表中已有的判重字段数据 exist_df = pd.read_sql("SELECT col1, col2, col3 FROM my_schema.my_table", con=engine) # 2. 关联对比得到本次需要新增的不重复数据 add_df = df.merge( exist_df, on=['col1', 'col2', 'col3'], # 和上面的判重字段保持一致 how='left', indicator=True ).query('_merge == "left_only"').drop(columns=['_merge']) # 3. 仅新增过滤后的新数据 add_df.to_sql('my_table', schema='my_schema', con=engine, if_exists='append', index=False, method='multi')
注意:方案2在数据量较大时查询全量表数据会有性能损耗,更推荐用方案1实现。
内容的提问来源于stack exchange,提问作者Lostsoul
相关产品推荐
相关产品推荐

