在 table 中插入非重复行而不删除 table
Inserting non duplicate rows in a table without dropping the table
我想在我的数据库中添加一个包含一些重复行的数据框,但是因为我的真实数据库非常大,所以我不想删除现有的 table 并使用更新后的数据再次添加它行,因为它需要我从 API
中再次拉出它
我认为正确的方法是 df.read_sql() 然后将结果与 df2 进行比较,然后只插入尚未存在的行
import sqlalchemy as db
import pandas as pd
engine = db.create_engine('sqlite:///test.db', echo = True)
data1 = {'Month':['June', 'July', 'August'],
'Number':[20, 21, 19]}
df = pd.DataFrame(data1)
df.to_sql("ExampleTable", engine,if_exists="append", index=False)
data2 = {'Month':['May','June', 'July', 'August', 'Septemper'],
'Number':[11, 20, 21, 19, 14, 15]}
df2 = pd.DataFrame(data2)
df2.to_sql("ExampleTable", engine,if_exists="append", index=False)
所以只是为了澄清一些事情。
SQLite 不会根据数据按顺序存储内容。它根据 ROW ID 存储它。但是,您可以检索数据,然后让 sqlite 根据 sql 查询中的列对返回的数据进行排序。
您要求插入数据,然后在第二个请求中修改或更新该数据。 Dataframes 并没有真正提供这种类型的功能。据我了解,pandas 可以插入到现有的 table 或删除 table 并插入新数据。因此,这很可能需要 运行 原始 sql 查询才能实现。此 post 显示有人在 sql 中为 pandas 执行所谓的“upsert”,但要求他们创建一个临时文件 table 并使用该文件 table 进行修改原始数据 table。
听起来这个问题归结为在新数据帧 df2
中查找不在原始数据帧 df
中的行,以便 df2
可以附加到现有的 sql table。 Stack Overflow 帖子 and here 中讨论了类似的数据帧比较场景。如果您只需要比较 'Month' 列,那么这应该有效:
df2_month_not_in_df = df2[~df2['Month'].isin(df['Month'])]
但是假设没有空 'Month' 值需要担心,不需要包括其他列,如年份等。一种更严格的方法可以比较多列的数据帧行,可能具有空值,按照 @toecsnar42 和其他人在上面的 SO 链接中的回答实施:
df_str_tuples = df.astype(str).apply(tuple, 1)
df2_str_tuples = df2.astype(str).apply(tuple, 1)
df2_rows_in_df_filter = df2_str_tuples.isin(df_str_tuples)
df2_rows_not_in_df = df2[~df2_rows_in_df_filter]
对于每个数据框,将所有值转换为字符串类型,这会将缺失值更改为 'nan',然后通过将每一列的值组合成每一行的单个元组来创建一个系列。接下来,创建一个掩码,只要 df2
有一行与 df
中的一行匹配,该掩码就为真。最后,将 df2
数据框过滤为仅掩码为假的行(即不在 df
中),这将构建数据框 df2_rows_not_in_df
,可以将其附加到现有的 sql table 使用 to_sql
和 if_exists="append"
。
过去帖子中的其他实现方法使用 pd.merge
或 pd.concat
方法,因此根据您的用例考虑不同的选项。
我想在我的数据库中添加一个包含一些重复行的数据框,但是因为我的真实数据库非常大,所以我不想删除现有的 table 并使用更新后的数据再次添加它行,因为它需要我从 API
中再次拉出它我认为正确的方法是 df.read_sql() 然后将结果与 df2 进行比较,然后只插入尚未存在的行
import sqlalchemy as db
import pandas as pd
engine = db.create_engine('sqlite:///test.db', echo = True)
data1 = {'Month':['June', 'July', 'August'],
'Number':[20, 21, 19]}
df = pd.DataFrame(data1)
df.to_sql("ExampleTable", engine,if_exists="append", index=False)
data2 = {'Month':['May','June', 'July', 'August', 'Septemper'],
'Number':[11, 20, 21, 19, 14, 15]}
df2 = pd.DataFrame(data2)
df2.to_sql("ExampleTable", engine,if_exists="append", index=False)
所以只是为了澄清一些事情。
SQLite 不会根据数据按顺序存储内容。它根据 ROW ID 存储它。但是,您可以检索数据,然后让 sqlite 根据 sql 查询中的列对返回的数据进行排序。
您要求插入数据,然后在第二个请求中修改或更新该数据。 Dataframes 并没有真正提供这种类型的功能。据我了解,pandas 可以插入到现有的 table 或删除 table 并插入新数据。因此,这很可能需要 运行 原始 sql 查询才能实现。此 post 显示有人在 sql 中为 pandas 执行所谓的“upsert”,但要求他们创建一个临时文件 table 并使用该文件 table 进行修改原始数据 table。
听起来这个问题归结为在新数据帧 df2
中查找不在原始数据帧 df
中的行,以便 df2
可以附加到现有的 sql table。 Stack Overflow 帖子
df2_month_not_in_df = df2[~df2['Month'].isin(df['Month'])]
但是假设没有空 'Month' 值需要担心,不需要包括其他列,如年份等。一种更严格的方法可以比较多列的数据帧行,可能具有空值,按照 @toecsnar42 和其他人在上面的 SO 链接中的回答实施:
df_str_tuples = df.astype(str).apply(tuple, 1)
df2_str_tuples = df2.astype(str).apply(tuple, 1)
df2_rows_in_df_filter = df2_str_tuples.isin(df_str_tuples)
df2_rows_not_in_df = df2[~df2_rows_in_df_filter]
对于每个数据框,将所有值转换为字符串类型,这会将缺失值更改为 'nan',然后通过将每一列的值组合成每一行的单个元组来创建一个系列。接下来,创建一个掩码,只要 df2
有一行与 df
中的一行匹配,该掩码就为真。最后,将 df2
数据框过滤为仅掩码为假的行(即不在 df
中),这将构建数据框 df2_rows_not_in_df
,可以将其附加到现有的 sql table 使用 to_sql
和 if_exists="append"
。
过去帖子中的其他实现方法使用 pd.merge
或 pd.concat
方法,因此根据您的用例考虑不同的选项。