【问题标题】:Python MySQLdb TypeError: not all arguments converted during string formattingPython MySQLdb TypeError:字符串格式化期间并非所有参数都转换
【发布时间】:2014-02-12 21:43:35
【问题描述】:

运行此脚本时:

#! /usr/bin/env python
import MySQLdb as mdb
import sys    

class Test:
    def check(self, search):
        try:
            con = mdb.connect('localhost', 'root', 'password', 'recordsdb');

            cur = con.cursor()
            cur.execute( "SELECT * FROM records WHERE email LIKE '%s'", search )

            ver = cur.fetchone()

            print "Output : %s " % ver

        except mdb.Error, e:

            print "Error %d: %s" % (e.args[0],e.args[1])
            sys.exit(1)

        finally:    
            if con:    
                con.close()

test = Test()
test.check("test")

我收到以下错误:

./lookup 
Traceback (most recent call last):
  File "./lookup", line 27, in <module>
    test.check("test")
  File "./lookup", line 11, in creep
    cur.execute( "SELECT * FROM records WHERE email LIKE '%s'", search )
  File "/usr/local/lib/python2.7/dist-packages/MySQLdb/cursors.py", line 187, in execute
    query = query % tuple([db.literal(item) for item in args])
TypeError: not all arguments converted during string formatting

我不知道为什么。我正在尝试进行参数化查询,但这只是一种痛苦。我对 Python 有点陌生,所以这可能是一个明显的问题。

【问题讨论】:

  • 不需要/不想引用您的查询参数。
  • cur.execute( "SELECT * FROM records WHERE email LIKE %s", [search])
  • 我在使用python2.7时遇到了这个问题,但是在使用python2.6时是正确的。你知道原因吗?
  • 在将我们服务器上的 Ubuntu 从 14.x 升级到 16.x 后,我也遇到了这个问题。有人可以在这里解释版本依赖关系吗?那真的很有帮助。

标签: python python-2.7


【解决方案1】:

你可以试试这个代码:

cur.execute( "SELECT * FROM records WHERE email LIKE %s", (search,) )

你可以看到the documentation

【讨论】:

  • 在元组末尾添加逗号正是我所需要的。
  • @User 感谢您指出这一点,真的很有帮助!以防其他人想知道;这是因为简单地在变量名周围添加 () 不会使其成为元组。添加逗号确实
  • 我必须添加方括号和逗号才能使其正常工作。
【解决方案2】:

而不是这个:

cur.execute( "SELECT * FROM records WHERE email LIKE '%s'", search )

试试这个:

cur.execute( "SELECT * FROM records WHERE email LIKE %s", [search] )

查看 MySQLdb documentation。原因是execute 的第二个参数表示要转换的对象列表,因为在参数化查询中可以有任意数量的对象。在这种情况下,您只有一个,但它仍然需要是一个可迭代的(元组而不是列表也可以)。

【讨论】:

  • 我明白了,所以必须传递一个列表才能使其工作?
  • 另外有趣的是,我仍然可以在输入中传递 % 并且它不会转义它,而是会像通配符一样使用它
  • @MandatoryProgrammer 不使用% 格式化查询字符串。使用上述方法。并来自文档the DB API requires you to pass in any parameters as a sequence.
  • 我不是,我指的是通过 search = "%test%" 有效(因此用户可以通过注入百分比符号作为输入来枚举我的数据库。
  • 您应该在执行前将您的查询转换为文本。我用同样的方法解决了我的问题。 \n >>> from sqlalchemy.sql import text >>> s = text( ... "SELECT users.fullname || ', ' ||addresses.email_address AS title " ... "FROM users, addresses " .. . "WHERE users.id =addresses.user_id" ... "AND users.name BETWEEN :x AND :y" ... "AND (addresses.email_address LIKE :e1" ... "ORaddresses.email_address LIKE :e2 )") SQL>>> conn.execute(s, x='m', y='z', e1='%@aol.com', e2='%@msn.com').fetchall()
【解决方案3】:

@kevinsa5 接受的答案是正确的,但你可能会想“我发誓这段代码使用过 可以工作,但现在不行了”,你是对的。

MySQLdb 库在 1.2.3 和 1.2.5 之间发生了 API 更改。支持的1.2.3版本

cursor.execute("SELECT * FROM foo WHERE bar = %s", 'baz')

但 1.2.5 版本需要

cursor.execute("SELECT * FROM foo WHERE bar = %s", ['baz'])

正如其他答案所述。我在更改日志中找不到更改,可能早期的行为被认为是错误。

Ubuntu 14.04 存储库具有 python-mysqldb 1.2.3,但 Ubuntu 16.04 及更高版本具有 python-mysqldb 1.3.7+。

如果您正在处理需要旧行为但您的平台是新的 Ubuntu 的遗留代码库,请改为从 PyPI 安装 MySQLdb:

$ pip install MySQL-python==1.2.3

【讨论】:

    【解决方案4】:

    '%' 关键字非常危险,因为它是'SQL INJECTION ATTACK' 的主要原因。
    所以你只是使用这段代码。

    cursor.execute("select * from table where example=%s", (example,))
    

    t = (example,)
    cursor.execute("select * from table where example=%s", t)
    

    如果你想尝试插入表格,试试这个。

    name = 'ksg'
    age = 19
    sex = 'male'
    t  = (name, age, sex)
    cursor.execute("insert into table values(%s,%d,%s)", t)
    

    【讨论】:

      【解决方案5】:
      cur.execute( "SELECT * FROM records WHERE email LIKE %s", (search,) )
      

      我不知道为什么,但这对我有用。而不是使用'%s'

      【讨论】:

        【解决方案6】:

        我不明白前两个答案。我认为它们必须依赖于版本。我无法在 Ubuntu 14.04LTS 附带的 MySQLdb 1.2.3 上重现它们。让我们试试看。首先,我们验证 MySQL 不接受双撇号:

        mysql> select * from methods limit 1;
        +----------+--------------------+------------+
        | MethodID | MethodDescription  | MethodLink |
        +----------+--------------------+------------+
        |       32 | Autonomous Sensing | NULL       |
        +----------+--------------------+------------+
        1 row in set (0.01 sec)
        
        mysql> select * from methods where MethodID = ''32'';
        ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '9999'' ' at line 1
        

        不。让我们尝试使用 /usr/lib/python2.7/dist-packages/MySQLdb/cursors.py 中的查询构造函数发布的 Mandatory 示例,其中我打开“con”作为与我的数据库的连接。

        >>> search = "test"
        >>> "SELECT * FROM records WHERE email LIKE '%s'" % con.literal(search)
        "SELECT * FROM records WHERE email LIKE ''test''"
        >>> 
        

        不,双撇号导致它失败。让我们试试 Mike Graham 的第一条评论,他建议去掉引用 %s 的撇号:

        >>> "SELECT * FROM records WHERE email LIKE %s" % con.literal(search)
        "SELECT * FROM records WHERE email LIKE 'test'"
        >>> 
        

        是的,这会起作用,但是 Mike 的第二条评论和文档说要执行的参数(由 con.literal 处理)必须是元组 (search,) 或列表 [search]。您可以尝试一下,但您会发现与上面的输出没有区别。

        最好的答案是ksg97031的。

        【讨论】:

        • ksg97031 也使用元组。它与 MySQLdb 库有关,而不是与 MySQL 本身有关。
        【解决方案7】:

        根据PEP8,我更喜欢这样执行SQL:

        cur = con.cursor()
        # There is no need to add single-quota to the surrounding of `%s`,
        # because the MySQLdb precompile the sql according to the scheme type
        # of each argument in the arguments list.
        sql = "SELECT * FROM records WHERE email LIKE %s;"
        args = [search, ]
        cur.execute(sql, args)
        

        这样,你会认识到execute方法的第二个参数args必须是一个参数列表。

        希望对您有所帮助。

        【讨论】:

          【解决方案8】:

          我在执行时遇到了这个错误 SELECT * FROM table; 我将错误追溯到 cursor.py 第 195 行。

          if args is not None:
                  if isinstance(args, dict):
                      nargs = {}
                      for key, item in args.items():
                          if isinstance(key, unicode):
                              key = key.encode(db.encoding)
                          nargs[key] = db.literal(item)
                      args = nargs
                  else:
                      args = tuple(map(db.literal, args))
                  try:
                      query = query % args
                  except TypeError as m:
                      raise ProgrammingError(str(m))
          

          鉴于我正在输入任何额外的参数,我摆脱了所有“if args ...”分支。现在它起作用了。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-10-28
            • 2013-10-21
            • 1970-01-01
            • 1970-01-01
            • 2017-08-13
            相关资源
            最近更新 更多