【问题标题】:Python Prepared Statements. Problems with SELECT INPython 准备好的语句。 SELECT IN 的问题
【发布时间】:2011-09-07 04:09:33
【问题描述】:

我在 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 语句被插入...

是否有可能解决准备好的语句的问题?

【问题讨论】:

    标签: python mysql sql prepared-statement


    【解决方案1】:

    我建议创建一个类型转换器来显式处理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'))
    

    【讨论】:

      【解决方案2】:

      参数列表中的每一项都需要一个占位符。
      您可以使用字符串操作来完成该部分:

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

      在下一步中,您可以按照DB-API documentation 中的建议将两个参数传递给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)
      

      【讨论】:

      • 这是个好主意!非常感谢!
      【解决方案3】:

      你想要

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

      即% 而不是逗号

      【讨论】:

      • 非常感谢!这也会阻止 SQL 注入吗?还是只会用 software_id_string 替换 %s?
      • 它只会将 %s 替换为 software_id_string。
      • 不要太迂腐,但不幸的是,这很容易受到 SQL 注入的影响。但即使您只有受信任的输入,推荐的方式(将单独的参数传递给execute())仍然是可取的,因为您不必手动管理值的引用,DB-API 将免费为您处理。
      • software_id_string变量是前行设置的,不是从用户那里获取的,所以我说没问题。
      猜你喜欢
      • 1970-01-01
      • 2011-07-13
      • 2014-06-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-02
      • 1970-01-01
      相关资源
      最近更新 更多