是否可以使用 pymysql 插入字典?
Is it possible to insert dictionary with pymysql?
我有一个字典,其名称和列与数据库中的相同。我可以按原样插入它,而不用再次手动输入所有列名重写 INSERT INTO
语句吗?
更新
问题是关于 pymysql
能力的。您不需要编写代码,从字典中构建 SQL
语句。
PyMySQL 和其他的一样 DB-API 2.0 adapter;参数必须作为位置或命名占位符放置在 SQL 查询中。如果您想避免预先明确命名列,则必须以编程方式生成占位符。
当您使用 %(name)s
参数语法时,PyMySQL 支持使用参数字典执行查询。要从字典生成插入语句,您可以使用:
def escape_name(s):
"""Escape name to avoid SQL injection and keyword clashes.
Doubles embedded backticks, surrounds the whole in backticks.
Note: not security hardened, caveat emptor.
"""
return '`{}`'.format(s.replace('`', '``'))
names = list(dict_of_params)
cols = ', '.join(map(escape_name, names)) # assumes the keys are *valid column names*.
placeholders = ', '.join(['%({})s'.format(name) for name in names])
query = 'INSERT INTO TABLENAME ({}) VALUES ({})'.format(cols, placeholders)
cursor.execute(query, dict_of_params)
我意识到这是一个相当古老的问题,但它是 Google 给我 'pymysql insert dictionary' 的最高结果所以我花了一些时间试图找出最好的方法以为我会分享。这是我第一次 post 来这里(尽管有 42 年的 DP/IT 经验!!)所以请对我温柔点:)
请注意,此答案特定于 pymysql - 据我了解,其他 mySQL/MariaDB 连接器可能会以不同方式处理绑定变量的替换(尽管应该可以调整 VALUES 上的连接参数以产生任何内容格式是必需的)。
假设 OP 描述的字典保存在一个名为 data 的变量中,这样说:
data = {'season' : 60, 'game' : 10, 'player' : 'JS1', 'runs' : 18}
并且我们在变量编写器中有一个现有的 pymysql 写入启用连接,那么这种通用方法应该会达到预期的结果:
writer.begin()
try:
with writer.cursor() as insert_cursor:
sqlcmd = (
f"INSERT INTO Scores ({', '.join(data.keys())}) "
f"VALUES (%({')s, %('.join(data.keys())})s)")
insert_cursor.execute(sqlcmd, data)
inserted = insert_cursor.rowcount
except:
writer.rollback()
print('\aScores table insert failed. Transaction rolled back')
raise
writer.commit()
print('Inserted', inserted, 'row(s) into Scores table')
如果我们将数据扩展为字典列表,那就更好了:
data = [
{'season' : 60, 'game' : 10, 'player' : 'JS1', 'runs' : 18},
{'season' : 60, 'game' : 12, 'player' : 'JS1', 'runs' : 0},
{'season' : 60, 'game' : 13, 'player' : 'JS1', 'runs' : 60},
...
]
然后通过一些小的调整,我们可以使用 executemany 在一次调用中将它们全部插入:
writer.begin()
try:
with writer.cursor() as insert_cursor:
sqlcmd = (
f"INSERT INTO Scores ({', '.join(data[0].keys())}) "
f"VALUES (%({')s, %('.join(data[0].keys())})s)")
insert_cursor.executemany(sqlcmd, data)
inserted = insert_cursor.rowcount
except:
writer.rollback()
print('\aScores table insert failed. Transaction rolled back')
raise
writer.commit()
print('Inserted', inserted, 'row(s) into Scores table')
我有一个字典,其名称和列与数据库中的相同。我可以按原样插入它,而不用再次手动输入所有列名重写 INSERT INTO
语句吗?
更新
问题是关于 pymysql
能力的。您不需要编写代码,从字典中构建 SQL
语句。
PyMySQL 和其他的一样 DB-API 2.0 adapter;参数必须作为位置或命名占位符放置在 SQL 查询中。如果您想避免预先明确命名列,则必须以编程方式生成占位符。
当您使用%(name)s
参数语法时,PyMySQL 支持使用参数字典执行查询。要从字典生成插入语句,您可以使用:
def escape_name(s):
"""Escape name to avoid SQL injection and keyword clashes.
Doubles embedded backticks, surrounds the whole in backticks.
Note: not security hardened, caveat emptor.
"""
return '`{}`'.format(s.replace('`', '``'))
names = list(dict_of_params)
cols = ', '.join(map(escape_name, names)) # assumes the keys are *valid column names*.
placeholders = ', '.join(['%({})s'.format(name) for name in names])
query = 'INSERT INTO TABLENAME ({}) VALUES ({})'.format(cols, placeholders)
cursor.execute(query, dict_of_params)
我意识到这是一个相当古老的问题,但它是 Google 给我 'pymysql insert dictionary' 的最高结果所以我花了一些时间试图找出最好的方法以为我会分享。这是我第一次 post 来这里(尽管有 42 年的 DP/IT 经验!!)所以请对我温柔点:)
请注意,此答案特定于 pymysql - 据我了解,其他 mySQL/MariaDB 连接器可能会以不同方式处理绑定变量的替换(尽管应该可以调整 VALUES 上的连接参数以产生任何内容格式是必需的)。
假设 OP 描述的字典保存在一个名为 data 的变量中,这样说:
data = {'season' : 60, 'game' : 10, 'player' : 'JS1', 'runs' : 18}
并且我们在变量编写器中有一个现有的 pymysql 写入启用连接,那么这种通用方法应该会达到预期的结果:
writer.begin()
try:
with writer.cursor() as insert_cursor:
sqlcmd = (
f"INSERT INTO Scores ({', '.join(data.keys())}) "
f"VALUES (%({')s, %('.join(data.keys())})s)")
insert_cursor.execute(sqlcmd, data)
inserted = insert_cursor.rowcount
except:
writer.rollback()
print('\aScores table insert failed. Transaction rolled back')
raise
writer.commit()
print('Inserted', inserted, 'row(s) into Scores table')
如果我们将数据扩展为字典列表,那就更好了:
data = [
{'season' : 60, 'game' : 10, 'player' : 'JS1', 'runs' : 18},
{'season' : 60, 'game' : 12, 'player' : 'JS1', 'runs' : 0},
{'season' : 60, 'game' : 13, 'player' : 'JS1', 'runs' : 60},
...
]
然后通过一些小的调整,我们可以使用 executemany 在一次调用中将它们全部插入:
writer.begin()
try:
with writer.cursor() as insert_cursor:
sqlcmd = (
f"INSERT INTO Scores ({', '.join(data[0].keys())}) "
f"VALUES (%({')s, %('.join(data[0].keys())})s)")
insert_cursor.executemany(sqlcmd, data)
inserted = insert_cursor.rowcount
except:
writer.rollback()
print('\aScores table insert failed. Transaction rolled back')
raise
writer.commit()
print('Inserted', inserted, 'row(s) into Scores table')