如何使用python mysqldb一次插入多行

Posted

技术标签:

【中文标题】如何使用python mysqldb一次插入多行【英文标题】:How to use python mysqldb to insert many rows at once 【发布时间】:2012-12-10 06:35:24 【问题描述】:

我有一个列表列表,例如[['a','b'],['c','d']]

我有一个名为T 的表和两个字段F1F2。字段列表中的第一项映射到F1,第二项映射到F2

如何在单个命令或调用中为每个内部列表插入行,而不是像这样使用 for 循环?

for i in [['a','b'],['c','d']]:
    c.execute("insert into T (F1,F2) values (%s, %s)", (i[0], i[1]))

【问题讨论】:

【参考方案1】:

来自mysqldb User's Guide:

c.executemany(
      """INSERT INTO breakfast (name, spam, eggs, sausage, price)
      VALUES (%s, %s, %s, %s, %s)""",
      [
      ("Spam and Sausage Lover's Plate", 5, 1, 8, 7.95 ),
      ("Not So Much Spam Plate", 3, 2, 0, 3.95 ),
      ("Don't Wany ANY SPAM! Plate", 0, 4, 3, 5.95 )
      ] )

所以在你的情况下:

c.executemany("insert into T (F1,F2) values (%s, %s)",
    [('a','b'),('c','d')])

【讨论】:

这是否比使用带有一些字符串操作的 mySQL 内置更有效?这样你的字符串是“插入到 T (F1,F2) 值 (a,b), (c,d) 中并将其传递给执行? @Jochen 您真的不想这样做,除非您绝对确定您的数据来自受信任的来源(而且我仍然相信“永远不要相信客户”是在任何情况下都要遵守的好规则)。通常情况下要好得多,至少当您使用像 MySQLdb 这样的成熟库时,将必要的引用/编码/转义留给 lib 而不是自己尝试;即使会产生一些开销,内心的平静也是值得的。 @Jochen 不要使用字符串操作将可能来自最终用户的数据包含到查询中。这是 SQL 注入漏洞的主要(如果不是唯一的)来源。训练自己以相反的方式思考:必须有一个非常、非常非常很好的理由来构建直接包含数据的查询,即使那样,你需要真的,真的确保最终用户根本不能包含 SQL,否则它将被转义。一个细微的错误可能是您的应用返回错误与返回电子邮件和密码哈希之间的区别。 要在 DB 中查看结果,您还必须添加 c.execute("COMMIT") 每行调用execute()12.2 分钟。调用 executemany(),每个查询有 32 行:9.9 分钟(快 19%)。自定义 SQL 代码:2.6 分钟(快 79%)。自定义 SQL 代码不安全并不是真的:con.escape_string() 就是为此目的而创建的。哎呀,它甚至不反对不受信任的输入,它还涉及正确处理常规输入中的任何撇号或引号。我的测试是用 400 万行完成的,在自定义 sql 代码测试中是 927MB 的 SQL 代码。【参考方案2】:

可以像@adamhajari 一样在一条语句中插入所有行,同时避免像@zenpoy 这样的sql 注入。你只需要创建一个大的插入语句,让mysqldb的execute进行格式化。

values_to_insert = [('a','b'),('c','d')]
query = "INSERT INTO T (F1, F2) VALUES " + ",".join("(%s, %s)" for _ in values_to_insert)
flattened_values = [item for sublist in values_to_insert for item in sublist]
c.execute(query, flattened_values)

可读性不强,但比 executemany 稍快(我尝试在本地数据库中插入 50000 行的批次,executemany 慢了 20%)。

【讨论】:

我认为某些数据库驱动程序无法处理超长参数列表。例如。 "pyodbc.Error: ('HY000', '驱动程序没有提供错误!')"【参考方案3】:
def multiple_insert(cursor, table, cols, rows):
    sql_insert = 'INSERT INTO %s(%s) values %s' % (
        table,
        ','.join(cols),
        ','.join('(%s , %s)' for _ in rows)
    )
    values = [_ for r in rows for _ in r]
    cursor.execute(sql_insert, values)


# eg:
rows = [(a1 , b1),(a2 , b2),(a3 , b3)]
multiple_insert(cursor, 'your_table',('col1', 'col2'), rows)
conn.commit()

【讨论】:

以上是关于如何使用python mysqldb一次插入多行的主要内容,如果未能解决你的问题,请参考以下文章

在 python 中使用 MySQLdb 插入 mysql 后,如何安全有效地获取行 ID?

在 python 中使用 MySQLdb 插入 mysql 后,如何安全有效地获取行 ID?

求助~~ INSERT INTO....SELECT怎么一次性插入多行数据

Python MySQLdb模块:不调用字符串格式可以插入或更新吗?

如何通过mysqldb将熊猫数据框插入数据库?

如何通过mysqldb将熊猫数据框插入数据库?