Python预处理语句:SELECT IN的问题

6 投票
3 回答
4001 浏览
提问于 2025-04-16 18:50

我在用Python写预处理语句的时候遇到了一个问题,到现在还没解决。

我想执行的查询大概是这样的:

 SELECT md5 FROM software WHERE software_id IN (1, 2, 4)

所以我试着执行了一个这样的查询:

software_id_string = "(2, 3, 4)"
cursor.execute("SELECT md5 FROM software WHERE software_id IN %s", 
                software_id_string)

问题是字符串里多了两个单引号——> '(2, 3, 4)',导致查询变成了:

SELECT md5 FROM software WHERE software_id IN ''(2, 3, 4)''

我还试着把脚本重写成这样:

software_id_string = " 1 OR software_id = 2"
cursor.execute("SELECT md5 FROm software WHERE software_id = %s", 
              software_id_string)

这样做只对第一个要提交的ID有效(在这个例子中是1),因为后面的OR部分没有被当作SQL语句来理解...

有没有什么办法可以解决预处理语句的问题呢?

3 个回答

0

你想要的是

cursor.execute("SELECT md5 FROM software WHERE software_id IN %s" % software_id_string)

也就是说,想要用百分号%来代替逗号

2

我建议你创建一个类型转换器,用来专门处理 IN 语句。这是 psycopg2 模块处理这个问题的方法:

from MySQLdb.converters import conversions

class SQL_IN(object):
    def __init__(self, seq):
        self.seq = seq

    @classmethod
    def escape(cls, obj, d):
        return '(' + ','.join((d[type(o)](o, d) for o in obj.seq)) + ')'

# add this before you call MySQLdb.connect()
conversions[SQL_IN] = SQL_IN.escape

真实的例子:

db = MySQLdb.connect()
cursor = db.cursor()

SQL = "SELECT * FROM emp WHERE emp_id IN %s"
in_values = (1, 2, 3)
cursor.execute(SQL, (SQL_IN(in_values),))
print cursor._last_executed
print cursor.fetchall()

SQL = "SELECT * FROM emp WHERE name IN %s"
in_values = ("bob", "fred")
cursor.execute(SQL, (SQL_IN(in_values),))
print cursor._last_executed
print cursor.fetchall()

输出结果:

SELECT * FROM emp WHERE emp_id IN (1,2,3)
((1L, 'bob'), (2L, 'larry'), (3L, 'fred'))
SELECT * FROM emp WHERE name IN ('bob','fred')
((1L, 'bob'), (3L, 'fred'))
8

你需要为参数列表中的每个项目准备一个占位符。
你可以使用字符串操作来完成这部分工作:

  1. 为每个参数创建一个 %s
  2. 然后用逗号把它们连接在一起。

接下来,你可以按照 DB-API 文档 的建议,把这两个参数传递给 execute() 方法。

software_id_string = (1,2,4)
qry = '''SELECT md5 
           FROM software 
          WHERE software_id IN (%s)''' % ','.join(['%s']*len(software_id_string))
# // 'SELECT md5 FROM software WHERE software_id IN (%s,%s,%s)'
cursor.execute(qry, software_id_string)

撰写回答