【问题标题】:How can I prevent extra quotations being inserted into MySQLdb statement from Python?如何防止从 Python 向 MySQLdb 语句中插入额外的引号?
【发布时间】:2015-12-27 11:50:13
【问题描述】:

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

【问题讨论】:

  • 或许可以试试:unit_ids = '("0A1", "0A2", "0A3", "0A4")'
  • 这很有趣。 print("""SELECT COUNT(*) FROM test WHERE attribute = %s AND unit_id IN %r""", (a, tuple(unit_ids))) 适合我,cur.execute 应该符合相同的语法。
  • 或添加尾随逗号并在执行字符串中仅使用 unit_ids 而不是 tuple(unit_ids)

标签: python mysql mysql-python


【解决方案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',),))

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

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

【讨论】:

  • 如果我在您的第一个代码块中运行代码,然后添加行 print(cur._last_executed) 以显示发送到数据库的确切 SQL 语句,我仍然看到 ...AND unit_id IN ("'0A'", "'0A2'", "'0A3'", "'0A4'")。该代码有效,因为它不会引发错误,但 unit_ids 中每个元素周围的附加引号会导致 select 语句不正确。
  • 我没有得到额外的引号(请参阅更新的答案)。您是否记得将您的 %r 更改为 %s
  • @zkstine 你使用了错误的参数%r。在构建查询时不要使用它。检查我的答案。
  • 也许您需要升级..? (我在 1.3.3)
  • @thebjorn 就是这样!升级 MySQLdb 后,就没有多余的引号了。谢谢!
【解决方案2】:

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

From the docs

在前面的示例中,我们将 SELECT 语句存储在变量查询中。请注意,我们在应有日期的地方使用了未加引号的 %s 标记。连接器/Python 将hire_start 和hire_end 从Python 类型转换为MySQL 可以理解的数据类型并添加所需的引号。在这种情况下,它将第一个 %s 替换为“1999-01-01”,第二个替换为“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')))

【讨论】:

  • 感谢您抽出宝贵时间回答@FallenAngel。 @thebjorn 已经指出我需要使用%s 而不是%r。现在我只想将整个变量 unit_ids 传递给 SQL 语句,而不是显式传递每个元素,但是当我这样做时,会在每个元素周围插入额外的引号。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-06-12
  • 1970-01-01
  • 1970-01-01
  • 2020-11-16
  • 2014-11-28
  • 2019-06-15
  • 1970-01-01
相关资源
最近更新 更多