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

时间:2015-09-29 20:45:14

标签: python mysql mysql-python

我需要使用MySQLdb从Python脚本运行一系列SQL select语句。我想传递给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语句中不再插入额外的引号。

2 个答案:

答案 0 :(得分:1)

你不需要任何魔法,只需按常规的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',),))

VS。使用列表(一个参数,该参数是一个项目列表):

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

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

更新:你必须以不同的方式做某事 ..这是cursor._last_executed的输出

>>> 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')"
>>>

答案 1 :(得分:0)

请勿在{{1​​}}中使用%r。在构建SQL查询时,Python-Mysql数据库API仅支持unit_id IN %r作为占位符。

From the docs

  

在前面的示例中,我们将SELECT语句存储在变量查询中。请注意,我们使用的是未标注的%s-markers,其中应该包含日期。 Connector / Python将hire_start和hire_end从 Python类型转换为MySQL理解的数据类型并添加所需的引号。在这种情况下,它用'1999-01-01'替换第一个%s,用'1999-12-31'替换第二个%s。

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

%s