【问题标题】:Is it possible to insert dictionary with pymysql?是否可以用 pymysql 插入字典?
【发布时间】:2018-02-25 16:08:49
【问题描述】:

我有一本与数据库中名称和列相同的字典。我可以按原样插入它,而不用再次手动键入所有列名重写INSERT INTO 语句吗?

更新

问题是关于pymysql 的功能。您无需编写代码,从字典中构建 SQL 语句。

【问题讨论】:

    标签: python mysql dictionary pymysql


    【解决方案1】:

    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)
    

    【讨论】:

    • @Dims:为什么会这样?您不能总是假设您有正确的列要插入。如果您省略了必填列怎么办?
    • 同我在 SQL 中省略了必填列
    【解决方案2】:

    我意识到这是一个相当老的问题,但它是 Google 为我提供的“pymysql 插入字典”的最佳结果,所以花了一些时间试图找出最好的方法,我想我会分享.这是我在这里的第一篇文章(尽管有 42 年的 DP/IT 经验!!)所以请对我温柔:)​​

    请注意,此答案特定于 pymysql - 据我了解,其他 mySQL/MariaDB 连接器可能会以不同方式处理绑定变量的替换(尽管应该可以调整 VALUES 上的连接参数以生成所需的任何格式) .

    假设 OP 描述的字典保存在一个名为 data 的变量中,这样说:

    data = {'season' : 60, 'game' : 10, 'player' : 'JS1', 'runs' : 18}
    

    并且我们在变量 writer 中有一个现有的 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')
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-04-26
      • 2017-03-23
      • 2019-10-05
      • 2013-06-24
      • 2018-10-14
      • 2013-12-27
      • 1970-01-01
      相关资源
      最近更新 更多