【问题标题】:WHERE IN clause in pymysql returns last rowpymysql 中的 WHERE IN 子句返回最后一行
【发布时间】:2019-06-29 09:13:09
【问题描述】:

考虑一个有 6 行的 users

   +_______________________+
   |     userid |  name    |
   +-----------------------+
   |       1    | john     |
   |       2    | steve    |
   |       3    | joe      |
   |       4    | jason    |
   |       5    | abraham  |
   |       6    | leonard  |
   +-----------------------+

我正在使用以下 SQL 查询:

SELECT userid,name FROM users where userid IN (2,3,4,5);

返回 4 行 -

   |       2    | steve    |
   |       3    | joe      |
   |       4    | jason    |
   |       5    | abraham  |

Pymysql 等效代码如下:

def get_username(user_ids):
    data=[]
    conn = init_db()
    cur = conn.cursor(pymysql.cursors.DictCursor)
    cur.executemany("SELECT userid,name from users WHERE userid IN (%s)",user_ids)
    rows=cur.fetchall()
    for row in rows:
        data.append([row['userid'],row['name']])
    cur.close()
    conn.close()
    return data

user_ids=[2,3,4,5]
get_usernames(user_ids)

这段代码只返回最后一行 [[5,abraham]] 。如何获取所有这些行?。

【问题讨论】:

    标签: python sql pymysql


    【解决方案1】:

    这是.executemany() 的(部分记录)行为:

    模块 pymysql.cursors 中方法 executemany 的帮助:

    pymysql.cursors.Cursor 实例的executemany(self, query, args)方法

    针对一个查询运行多个数据

    :param query: 在服务器上执行的查询

    :param args:序列或映射的序列。用作参数。

    :return: 受影响的行数,如果有的话。

    此方法提高了多行 INSERT 和 代替。否则,它相当于在 args 上循环 执行()。

    所以你想要的是cursor.execute() - 但是,你需要做更多的工作来构建你的 SQL 查询:

    user_ids = (2, 3, 4, 5)
    placeholders = ", ".join(["%s"] * len(user_ids)) 
    sql = "SELECT userid,name from users WHERE userid IN ({})".format(placeholders)
    cursor.execute(sql, user_ids)
    data = list(cursor)
    

    注意游标是可迭代的,所以你不需要显式调用cursor.fetchall()然后迭代结果,你可以直接在游标上迭代。另请注意,如果您想要(id, name) 元组的列表,使用DictCursor 只是CPU 周期的双重浪费(一次用于构建字典,一次用于重建元组),您可以只使用默认游标并返回list(cursor)

    【讨论】:

      【解决方案2】:

      我的第一个猜测是与 SELECT 语句有关。 您可以尝试这种生成查询的方式吗?

      def get_username(user_ids):
          data=[]
          conn = init_db()
          cur = conn.cursor(pymysql.cursors.DictCursor)
          cur.executemany("SELECT userid,name from users WHERE userid IN "+"("+','.join(str(e) for e in user_ids)+")")
          rows=cur.fetchall()
          for row in rows:
              data.append([row['userid'],row['name']])
          cur.close()
          conn.close()
          return data
      
      user_ids=[2,3,4,5]
      get_usernames(user_ids)
      

      【讨论】:

      • 为什么投反对票?我也猜想,我们需要 %s 的字符串,而不是数组。所以从数组中构建字符串。 (不过,我不知道这个答案在语法上是否正确,因为我不了解 Python。它是否从值中构建了一个逗号分隔的字符串?无论如何,我认为这种方法是有意义的。)
      • 为什么投反对票:您刚刚绕过了针对 SQL 注入的内置保护,让您的应用程序为第一个脚本小子打开。阅读本文以获取有关该主题的更多信息:bobby-tables.com
      • 仅供参考:传递给cursor.execute() 的 SQL 查询中的“%s”占位符不是(用作)字符串格式化运算符(很遗憾他们选择将其用作占位符而不是'?',因为它显然让每个人都感到困惑),它实际上只是一个占位符。
      • 最后:当我们讨论字符串格式化时,请学习使用 Python 的格式化功能,它们使您的代码比字符串连接更具可读性 ;-)
      • 很好的答案谢谢你们的反馈!
      猜你喜欢
      • 1970-01-01
      • 2012-08-04
      • 2020-06-23
      • 2014-02-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-08
      • 2013-07-19
      相关资源
      最近更新 更多