如何防止从 Python 向 MySQLdb 语句中插入额外的引号?

How can I prevent extra quotations being inserted into MySQLdb statement from Python?

我有一系列 SQL select 语句,我需要使用 MySQLdb 从 Python 脚本中 运行。我想传递给 select 语句的变量之一称为 unit_ids。我试过将 unit_ids 视为一个字符串以及一个字符串元组。最初,反斜杠被插入到字符串中。在线查看后,我已经能够避免使用反斜杠,但现在插入了额外的引号。这是我当前的代码:

connection = MySQLdb.connect('localhost', 'root', '*****', 'test')
cur = connection.cursor

unit_ids = ('0A1', '0A2', '0A3', '0A4')
attr = 'sample'

cur.execute("""SELECT COUNT(*) FROM test WHERE attribute = %s AND unit_id IN %r""", (a, tuple(unit_ids)))

使用 cur._last_executed,我可以看到实际执行的 SQL 语句是:

SELECT COUNT(*) FROM test WHERE attribute = 'sample' AND unit_id IN ("'0A1'", "'0A2'", "'0A3'", "'0A4'")

为了让 ('0A1', '0A2', '0A3', '0A4') 在 SQL 声明中保持不变,我需要更改什么?

更新:这是我在使用 %s:

时得到的准确输出
>>> cn = MySQLdb.connect('localhost', 'root', '***', '***')
>>> c = cn.cursor()
>>> unit_ids = ('0A1', '0A2', '0A3', '0A4')
>>> a = 'foo'
>>> c.execute("""select count(*) from model_test where attribute = %s and unit_id in %s""", (a, unit_ids))
1L
>>> print(c._last_executed)
select count(*) from model_test where attribute = 'foo' and unit_id in ("'0A1'", "'0A2'", "'0A3'", "'0A4'")

在这一点上,我想我可能只需要为 unit_ids 的每个元素创建单独的变量(例如 unit_id1 = '0A1')。顺便说一下,我正在使用 Python 2.7.9 和 MySQL Server 5.6。



更新 2:@thebjorn 解决了它:我的 MySQLdb 版本已经过时了。升级后,SQL语句中不再插入额外的引号。

您不需要任何魔法,只需按常规 mysql 方式进行即可:

connection = MySQLdb.connect('localhost', 'root', '*****', 'test')
cur = connection.cursor()

unit_ids = ('0A1', '0A2', '0A3', '0A4')
attr = 'sample'

cur.execute("""SELECT COUNT(*) FROM test WHERE attribute = %s AND unit_id IN %s""", (a, unit_ids))

我能看到的唯一问题是,如果未包含 a 并且 unit_ids 只有一项,那么元组语法可能会让您感到困惑。如果您将 unit_ids 放入列表中,那么语法就不会那么尴尬了:

unit_ids = ('0A1',)
cur.execute("SELECT COUNT(*) FROM test WHERE unit_id IN %s", (unit_ids,))

内联后变为:

cur.execute("SELECT COUNT(*) FROM test WHERE unit_id IN %s", (('0A1',),))

对比使用列表(一个参数,该参数是一项列表):

cur.execute("SELECT COUNT(*) FROM test WHERE unit_id IN %s", [['0A1']])

您可以对所有 mysql 参数使用 %s(也可以使用其他一些参数,但不能使用 %r -- 这不是字符串插值)。

更新:你一定在做一些事情和我不一样..这是cursor._last_executed[=20的输出=]

>>> cn = MySQLdb.connect('server', 'user', 'password', 'database')
>>> c = cn.cursor()
>>> unit_ids = ('0A1', '0A2', '0A3', '0A4')
>>> c.execute("select count(*) from foo where id in %s", (unit_ids,))
Traceback (most recent call last):
  File ...
_mysql_exceptions.ProgrammingError: (1146, "Table 'djangodevelop.foo' doesn't exist")
>>> c._last_executed
"select count(*) from foo where id in ('0A1','0A2','0A3','0A4')"
>>>

不要在 unit_id IN %r 中使用 %r。 Python-Mysql 数据库 API 在构建 SQL 查询时仅支持 %s 作为占位符。

From the docs

In the preceding example, we store the SELECT statement in the variable query. Note that we are using unquoted %s-markers where dates should have been. Connector/Python converts hire_start and hire_end from Python types to a data type that MySQL understands and adds the required quotes. In this case, it replaces the first %s with '1999-01-01', and the second with '1999-12-31'.

您可以在 Python-MySql docs 中看到类似的警告和用法。

cur.execute("""
    SELECT COUNT(*) FROM test WHERE attribute = %s AND unit_id IN %s
""", (a, ('0A1', '0A2', '0A3', '0A4')))