Pandas: 使用to_sql()时,如果检测到重复的主键,是否继续?

创建于 2017-04-13  ·  19评论  ·  资料来源: pandas-dev/pandas

代码示例,如果可能的话,一个可复制粘贴的示例

df.to_sql('TableNameHere', engine, if_exists='append', chunksize=900, index=False)

问题描述

我正在尝试将大型 DataFrame 附加到 SQL 表中。 DataFrame 中的某些行与 SQL 表中的行重复,有些则不是。 但是,即使检测到一个重复项, to_sql()也会完全停止执行。

to_sql(if_exists='append')仅警告用户哪些行具有重复键并继续添加新行而不完全停止执行是有意义的。 对于大型数据集,您可能会有重复但想忽略它们。

也许添加一个参数来忽略重复并继续执行? 也许像'append_skipdupes'这样的额外if_exists选项?

pd.show_versions()的输出

安装版本

提交:无
蟒蛇:3.6.0.final.0
蟒蛇位:64
操作系统:Windows
操作系统版本:10
机器:AMD64
处理器:Intel64 Family 6 Model 60 Stepping 3, GenuineIntel
字节序:很少
LC_ALL:无
朗:无
语言环境:English_United States.1252

熊猫:0.19.2
鼻子:无
点数:9.0.1
设置工具:28.8.0
赛通:无
麻木:1.12.0
scipy:无
统计模型:无
xarray:无
IPython:5.3.0
狮身人面像:无
帕西:无
日期工具:2.6.0
皮茨:2016.10
块:无
瓶颈:无
表:无
numexpr:无
matplotlib:无
openpyxl:无
xlrd:无
xlwt:无
xlsxwriter:无
lxml:无
bs4:无
html5lib: 0.999999999
httplib2:无
apiclient:无
sqlalchemy:1.1.9
pymysql:无
psycopg2:无
神社2:2.9.5
博托:无
pandas_datareader:无

Enhancement IO SQL

最有用的评论

这也应该支持“重复更新”模式。

所有19条评论

这也应该支持“重复更新”模式。

@rostripi我认为这个想法肯定会被接受,但AFAIK的主要瓶颈是使用sql / sqlalchemy以一种与风格无关的方式实现这一点。 一些探索如何做到这一点当然是受欢迎的!

嗨,你有没有找到任何解决方法? 请告诉我

此实施的任何更新?

我现在正面临 PostgreSQL 和 SQLAlchemy 的这个问题,并且希望能够“重复更新”。

感谢您的工作

一种解决方法是删除数据库中的唯一索引:

sqlquery="ALTER 'TABLE DATABASE'.'TABLE' DROP INDEX 'idx_name'"
然后
df.to_sql('TableNameHere', engine, if_exists='append', chunksize=900, index=False)
可以执行。

只需让您的 MySQL 服务器再次添加索引并删除重复项。
sqlquery="ALTER IGNORE TABLE 'DATABASE'.'TABLE' ADD UNIQUE INDEX 'idx_name' ('column_name1' ASC, 'column_name2' ASC, 'column_name3' '[ASC | DESC]')"

根据您的具体应用,这可能会有所帮助。
无论如何,像append_skipdupes这样的if_exists选项会好得多。

append_skipdupes将是处理此问题的完美方法。

是的,append_skipdupes +1

同意能够使用df.to_sql()中的选项来处理这个问题会很好。

这是我在 sqlite 中使用的解决方法:

CREATE TABLE IF NOT EXISTS my_table_name (
    some_kind_of_id INT PRIMARY KEY ON CONFLICT IGNORE,
    ...

然后,当我插入重复项时,它们会被默默地忽略,并且正确处理非重复项。 就我而言,数据是(即应该是)静态的,所以我不需要更新。 只是数据馈送的形式是这样的,我会得到可忽略的重复项。

MariaDb 和 MySql 的另一种解决方法:
df.to_csv("test.csv")
然后使用:
LOAD DATA INFILE 'test.csv' IGNORE INTO TABLE mytable
LOAD DATA INFILE 'test.csv' REPLACE INTO TABLE mytable

LOAD DATA 比 INSERT 快得多。

完整代码:

csv_path = str(Path(application_path) / "tmp" / "tmp.csv").replace("\\", "\\\\")
df.to_csv(csv_path, index=False, sep='\t', quotechar="'", na_rep=r'\N')
rq = """LOAD DATA LOCAL INFILE '{file_path}' REPLACE INTO TABLE {db}.{db_table}
        LINES TERMINATED BY '\\r\\n'
        IGNORE 1 LINES
         ({col});
        """.format(db=db,
                   file_path=csv_path,
                   db_table=table_name,
                   col=",".join(df.columns.tolist()))

我相信这是在 #29636 中使用upsert_ignore参数解决的,该参数解决了 #14553。

append_skipdupes +1

+1 为 append_skipdupes

同意应该添加“append_skipdupes”。

是的,请。 应该添加“append_skipdupes”,而不仅仅是主键列。 如果其他唯一列之间存在重复,它也应该跳过附加那些新的重复行。

+1 为 append_skipdupes

append_skipdupes +1

append_skipdupes +1

+1 为 append_skipdupes

同时你可以使用这个https://pypi.org/project/pangres/

此页面是否有帮助?
0 / 5 - 0 等级