【问题标题】:Parameterized query with pyodbc and mysql8 returns 0 for columns with int data types使用 pyodbc 和 mysql8 的参数化查询对于具有 int 数据类型的列返回 0
【发布时间】:2019-11-02 18:57:11
【问题描述】:
  • Python:2.7.12
  • pyodbc: 4.0.24
  • 操作系统:Ubuntu 16.4
  • 数据库:MySQL 8
  • 驱动程序:MySQL 8

预期行为:结果集应在数据类型为 int 的列中包含数字

实际行为:所有int数据类型的列都有0的(如果使用参数化查询)

这是查询 -

    1.
cursor.execute("SELECT * FROM TABLE where id =7")

结果集:

[(7, 1, None, 1, u'An', u'Zed', None, u'Ms', datetime.datetime(2016, 12, 20, 0, 0), u'F', u'Not To Be Disclosed', None, None, u'SPRING', None, u'4000', datetime.datetime(2009, 5, 20, 18, 55), datetime.datetime(2019, 1, 4, 14, 25, 58, 763000), 0, None, None, None, bytearray(b'\x00\x00\x00\x00\x01(n\xba'))]
    2.
cursor.execute("SELECT * FROM patients where patient_id=?", [7])`

cursor.execute("SELECT * FROM patients where patient_id=?", ['7'])

cursor.execute("SELECT * FROM patients where patient_id IN ", [7])

结果集:

[(0, 0, None, 0, u'An', u'Zed', None, u'Ms', datetime.datetime(2016, 12, 20, 0, 0), u'F', u'Not To Be Disclosed', None, None, u'SPRING', None, u'4000', datetime.datetime(2009, 5, 20, 18, 55), datetime.datetime(2019, 1, 4, 14, 25, 58, 763000), 0, None, None, None, bytearray(b'\x00\x00\x00\x00\x01(n\xba'))]

如果使用参数化查询,则结果集的其余部分都可以,但具有 int 数据类型的列全部为 0。

似乎它应该可以正常工作。我可以在这里寻求帮助吗?

编辑:这是表的架构:

 CREATE TABLE `patient
  `lastname` varchar(30) DEFAULT NULL,
  `known_as` varchar(30) DEFAULT NULL,
  `title` varchar(50) DEFAULT NULL,
  `dob` datetime DEFAULT NULL,
  `sex` char(1) DEFAULT NULL,
  `address1` varchar(30) DEFAULT NULL,
  `address2` varchar(30) DEFAULT NULL,
  `address3` varchar(30) DEFAULT NULL,
  `city` varchar(30) DEFAULT NULL,
  `state` varchar(16) DEFAULT NULL,
  `postcode` char(4) DEFAULT NULL,
  `datecreated` datetime NOT NULL,
  `dateupdated` datetime(6) DEFAULT NULL,
  `isrep` tinyint(1) DEFAULT NULL,
  `photo` longblob,
  `foreign_images_imported` tinyint(1) DEFAULT NULL,
  `ismerged` tinyint(1) DEFAULT NULL,
  `rowversion` varbinary(8) DEFAULT NULL,
  PRIMARY KEY (`patient_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

【问题讨论】:

  • @snakecharmerb 如果您需要更多信息,请告诉我
  • 但这对我来说似乎是相当基本的用例。人们如何应对它?
  • 我怀疑大多数从 Python 使用 MySQL 的人都在使用 mysqlclient 而不是 pyodbc。

标签: python mysql pyodbc


【解决方案1】:

您在 MySQL 连接器/ODBC 中遇到过this bug

编辑:错误has now been fixed


以下 (Python 3) 测试代码验证 MySQL Connector/ODBC 返回零(不正确),而 mysqlclient 返回正确值:

import MySQLdb  # from mysqlclient
import pyodbc

host = 'localhost'
user = 'root'
passwd = 'whatever'
db = 'mydb'
port = 3307
charset = 'utf8mb4'

use_odbc = False  # or True
print(f'{"" if use_odbc else "not "}using ODBC ...')

if use_odbc:
    connection_string = (
        f'DRIVER=MySQL ODBC 8.0 ANSI Driver;'
        f'SERVER={host};UID={user};PWD={passwd};DATABASE={db};PORT={port};'
        f'charset={charset};'
    )
    cnxn = pyodbc.connect(connection_string)
    print(f'{cnxn.getinfo(pyodbc.SQL_DRIVER_NAME)}, version {cnxn.getinfo(pyodbc.SQL_DRIVER_VER)}')
else:
    cnxn = MySQLdb.connect(
        host=host, user=user, passwd=passwd, db=db, port=port, charset=charset
    )

int_value = 123
crsr = cnxn.cursor()
crsr.execute("CREATE TEMPORARY TABLE foo (id varchar(10) PRIMARY KEY, intcol int, othercol longblob)")
crsr.execute(f"INSERT INTO foo (id, intcol) VALUES ('Alfa', {int_value})")
sql = f"SELECT intcol, othercol FROM foo WHERE id = {'?' if use_odbc else '%s'}"
crsr.execute(sql, ('Alfa',))
result = crsr.fetchone()[0]
print(f'{"pass" if result == int_value else "FAIL"} -- expected: {repr(int_value)} ; actual: {repr(result)}')

use_odbc = True 的控制台输出:

using ODBC ...
myodbc8a.dll, version 08.00.0018
FAIL -- expected: 123 ; actual: 0

use_odbc = False 的控制台输出:

not using ODBC ...
pass -- expected: 123 ; actual: 123

【讨论】:

  • 感谢您的回复。我试了一下,得到以下错误:>>> cursor.execute("SELECT * FROM patients where patient_id=?", ('7',)) Traceback (last recent call last): File "", line 1 ,在 文件“/usr/lib/python2.7/dist-packages/MySQLdb/cursors.py”中,第 210 行,在执行 query = query % args TypeError:字符串格式化期间并非所有参数都转换了@Gord Thompson
  • 看起来 MySQLdb 使用 %s 而不是 ?在参数化查询中。你能确认@Gord Thompson
  • @Simrankaur re:参数占位符 - 是的,你是对的。
  • 那么有没有办法不用修改参数占位符就可以使用MySQLdb呢?我本来希望避免在我的所有查询中进行此更改@Gord Thompson
  • 我在 MySQL 中创建了您的“患者”表并尝试重现您的问题,但我无法使用 MySQL 连接器/ODBC 8.00.18(通过 pyodbc)或使用 mysqlclient。在任何情况下,ODBC 8.x 的另一种可能的解决方法是首先仅选择 int 列,然后执行第二次 SELECT 以检索相同行的剩余列。或者,您可以回退到动态 SQL,对于像 SELECT * ... WHERE patient_id = 7 这样的查询不会造成 SQL 注入问题的重大风险。
【解决方案2】:

FWIW 我刚刚发布了一个问题,我在 ODBC 连接器的 3.1.14 版中看到了这个问题,但在 3.1.10 版中没有。

【讨论】:

  • 啊,我正在为 MySQL 8 使用 ODBC 连接器 8
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-25
  • 2012-03-08
相关资源
最近更新 更多