如何转换 pandas 数据帧以通过 executemany() 语句插入?
how to transform pandas dataframe for insertion via executemany() statement?
我有相当大的 pandas dataframe - 50
左右 header 和几十万行数据 - 我希望将这些数据传输到数据库使用ceODBC
模块。以前我使用 pyodbc
并在 for 循环中使用一个简单的执行语句,但这花费的时间长得离谱(每 10 分钟 1000 条记录)...
我现在正在尝试一个新模块并尝试引入 executemany()
尽管我不太确定以下参数序列的含义:
cursor.executemany("""insert into table.name(a, b, c, d, e, f)
values(?, ?, ?, ?, ?), sequence_of_parameters)
它应该看起来像一个常量列表,遍历每个 header like
['asdas', '1', '2014-12-01', 'true', 'asdasd', 'asdas', '2',
'2014-12-02', 'true', 'asfasd', 'asdfs', '3', '2014-12-03', 'false', 'asdasd']
- 这是三行的示例
或者需要什么格式?
作为另一个相关问题,我该如何将常规 pandas 数据帧转换为这种格式?
谢谢!
你可以试试这个:
cursor.executemany(sql_str, your_dataframe.values.tolist())
希望对您有所帮助。
最后我设法解决了这个问题。
所以如果你有一个 Pandas 数据框,你想使用 ceODBC
写入数据库,这是我使用的模块,代码是:
(以 all_data
作为数据帧)将数据帧值映射到字符串并将每一行作为元组存储在元组列表中
for r in all_data.columns.values:
all_data[r] = all_data[r].map(str)
all_data[r] = all_data[r].map(str.strip)
tuples = [tuple(x) for x in all_data.values]
对于元组列表,将所有空值指示符(在上面的转换中被捕获为字符串)更改为可以传递给最终数据库的空类型。这对我来说是个问题,可能不适合你。
string_list = ['NaT', 'nan', 'NaN', 'None']
def remove_wrong_nulls(x):
for r in range(len(x)):
for i,e in enumerate(tuples):
for j,k in enumerate(e):
if k == x[r]:
temp=list(tuples[i])
temp[j]=None
tuples[i]=tuple(temp)
remove_wrong_nulls(string_list)
创建到数据库的连接
cnxn=ceODBC.connect('DRIVER={SOMEODBCDRIVER};DBCName=XXXXXXXXXXX;UID=XXXXXXX;PWD=XXXXXXX;QUIETMODE=YES;', autocommit=False)
cursor = cnxn.cursor()
定义一个函数,将元组列表转换为 new_list
,这是对元组列表的进一步索引,转换为 1000 个块。这对于我将数据传递到数据库是必要的SQL 查询不能超过 1MB。
def chunks(l, n):
n = max(1, n)
return [l[i:i + n] for i in range(0, len(l), n)]
new_list = chunks(tuples, 1000)
定义您的查询。
query = """insert into XXXXXXXXXXXX("XXXXXXXXXX", "XXXXXXXXX", "XXXXXXXXXXX") values(?,?,?)"""
运行 通过 new_list
包含以 1000 为一组的元组列表并执行 executemany
。通过提交并关闭连接来执行此操作,仅此而已:)
for i in range(len(new_list)):
cursor.executemany(query, new_list[i])
cnxn.commit()
cnxn.close()
回答这个问题可能有点晚,但也许它仍然可以帮助到某人。 executemany()
没有被许多 ODBC 实现。 MySQL
确实拥有它的其中之一。当他们提到参数序列时,他们的意思是:
parameters=[{'name':'Jorge', 'age':22, 'sex':'M'},
{'name':'Karen', 'age':25, 'sex':'F'},
{'name':'James', 'age':29, 'sex':'M'}]
对于查询语句,它看起来像:
SQL = INSERT IGNORE INTO WORKERS (NAME, AGE, SEX) VALUES (%(name)s, %(age)s, %(sex)s)
看起来你到了那里。不过我想指出几件事以防万一:
pandas 有一个 to_sql 函数,如果您向它提供连接器对象,它会插入到数据库中,并将数据分块。
为了从 pandas 数据帧快速创建一系列参数,我发现以下两种方法很有用:
# creates list of dict, list of parameters
# REF: https://groups.google.com/forum/#!topic/pydata/qna3Z3WmVpM
parameters = [df.iloc[line, :].to_dict() for line in range(len(df))]
# Cleaner Way
parameters = df.to_dict(orient='records')
概括一点以确保查询和数据框的列顺序相同:
columns = ','.join(df.columns)
values=','.join([':{:d}'.format(i+1) for i in range(len(df.columns))])
sql = 'INSERT INTO table.name({columns:}) VALUES ({values:})'
cursor.executemany(sql.format(columns=columns, values=values), df.values.tolist())
我有相当大的 pandas dataframe - 50
左右 header 和几十万行数据 - 我希望将这些数据传输到数据库使用ceODBC
模块。以前我使用 pyodbc
并在 for 循环中使用一个简单的执行语句,但这花费的时间长得离谱(每 10 分钟 1000 条记录)...
我现在正在尝试一个新模块并尝试引入 executemany()
尽管我不太确定以下参数序列的含义:
cursor.executemany("""insert into table.name(a, b, c, d, e, f)
values(?, ?, ?, ?, ?), sequence_of_parameters)
它应该看起来像一个常量列表,遍历每个 header like
['asdas', '1', '2014-12-01', 'true', 'asdasd', 'asdas', '2',
'2014-12-02', 'true', 'asfasd', 'asdfs', '3', '2014-12-03', 'false', 'asdasd']
- 这是三行的示例
或者需要什么格式?
作为另一个相关问题,我该如何将常规 pandas 数据帧转换为这种格式?
谢谢!
你可以试试这个:
cursor.executemany(sql_str, your_dataframe.values.tolist())
希望对您有所帮助。
最后我设法解决了这个问题。
所以如果你有一个 Pandas 数据框,你想使用 ceODBC
写入数据库,这是我使用的模块,代码是:
(以 all_data
作为数据帧)将数据帧值映射到字符串并将每一行作为元组存储在元组列表中
for r in all_data.columns.values:
all_data[r] = all_data[r].map(str)
all_data[r] = all_data[r].map(str.strip)
tuples = [tuple(x) for x in all_data.values]
对于元组列表,将所有空值指示符(在上面的转换中被捕获为字符串)更改为可以传递给最终数据库的空类型。这对我来说是个问题,可能不适合你。
string_list = ['NaT', 'nan', 'NaN', 'None']
def remove_wrong_nulls(x):
for r in range(len(x)):
for i,e in enumerate(tuples):
for j,k in enumerate(e):
if k == x[r]:
temp=list(tuples[i])
temp[j]=None
tuples[i]=tuple(temp)
remove_wrong_nulls(string_list)
创建到数据库的连接
cnxn=ceODBC.connect('DRIVER={SOMEODBCDRIVER};DBCName=XXXXXXXXXXX;UID=XXXXXXX;PWD=XXXXXXX;QUIETMODE=YES;', autocommit=False)
cursor = cnxn.cursor()
定义一个函数,将元组列表转换为 new_list
,这是对元组列表的进一步索引,转换为 1000 个块。这对于我将数据传递到数据库是必要的SQL 查询不能超过 1MB。
def chunks(l, n):
n = max(1, n)
return [l[i:i + n] for i in range(0, len(l), n)]
new_list = chunks(tuples, 1000)
定义您的查询。
query = """insert into XXXXXXXXXXXX("XXXXXXXXXX", "XXXXXXXXX", "XXXXXXXXXXX") values(?,?,?)"""
运行 通过 new_list
包含以 1000 为一组的元组列表并执行 executemany
。通过提交并关闭连接来执行此操作,仅此而已:)
for i in range(len(new_list)):
cursor.executemany(query, new_list[i])
cnxn.commit()
cnxn.close()
回答这个问题可能有点晚,但也许它仍然可以帮助到某人。 executemany()
没有被许多 ODBC 实现。 MySQL
确实拥有它的其中之一。当他们提到参数序列时,他们的意思是:
parameters=[{'name':'Jorge', 'age':22, 'sex':'M'},
{'name':'Karen', 'age':25, 'sex':'F'},
{'name':'James', 'age':29, 'sex':'M'}]
对于查询语句,它看起来像:
SQL = INSERT IGNORE INTO WORKERS (NAME, AGE, SEX) VALUES (%(name)s, %(age)s, %(sex)s)
看起来你到了那里。不过我想指出几件事以防万一: pandas 有一个 to_sql 函数,如果您向它提供连接器对象,它会插入到数据库中,并将数据分块。
为了从 pandas 数据帧快速创建一系列参数,我发现以下两种方法很有用:
# creates list of dict, list of parameters
# REF: https://groups.google.com/forum/#!topic/pydata/qna3Z3WmVpM
parameters = [df.iloc[line, :].to_dict() for line in range(len(df))]
# Cleaner Way
parameters = df.to_dict(orient='records')
概括一点以确保查询和数据框的列顺序相同:
columns = ','.join(df.columns)
values=','.join([':{:d}'.format(i+1) for i in range(len(df.columns))])
sql = 'INSERT INTO table.name({columns:}) VALUES ({values:})'
cursor.executemany(sql.format(columns=columns, values=values), df.values.tolist())