栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

MySQLdb不会返回所有用“在重复键更新时”转换的参数

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

MySQLdb不会返回所有用“在重复键更新时”转换的参数

怎么了

在检查了下面注释中的链接并进行了更多的研究和测试之后,我能够使用MySQLdb版本1.2.4b4和1.2.5重现该错误。如unubtu的答案所述,这与出现在中的正则表达式的局限性有关

cursors.py
。各个版本中的确切正则表达式略有不同,这可能是因为人们一直在寻找它无法处理的情况并调整表达式,而不是完全寻找更好的方法。

正则表达式的作用是尝试匹配语句的

VALUES ( ...)
子句,
INSERT
并标识其包含的元组表达式的开头和结尾。如果匹配成功,则
executemany
尝试将单行插入语句模板转换为多行插入语句,以使其运行更快。即,不要对要插入的每一行执行此操作:

INSERT INTO table  (foo, bar, ...)VALUES  (%s, %s, ...);

它尝试重写该语句,以便只执行一次:

INSERT INTO table  (foo, bar, ...)VALUES  (1, 2, ...),  (3, 4, ...),  (5, 6, ...),  ...;

您遇到的问题是,

executemany
假设紧随在元组中只有参数占位符
VALUES
。当您以后还有占位符时,它将执行以下操作:

INSERT INTO table  (foo, bar, ...)VALUES  (%s, %s, ...)ON DUPLICATE KEY UPDATE baz=%s;

并尝试像这样重写它:

INSERT INTO table  (foo, bar, ...)VALUES  (1, 2, ...),  (3, 4, ...),  (5, 6, ...),  ...ON DUPLICATE KEY UPDATE baz=%s;

这里的问题是MySQLdb在重写查询的同时尝试进行字符串格式化。只有

VALUES ( ... )
子句需要重写,因此MySQLdb尝试将 所有
参数放入匹配的组中
(%s, %s, ...)
,而没有意识到有些参数需要放入
UPDATE
子句中。

如果您仅将

VALUES
子句的参数发送到
executemany
,则可以避免,
TypeError
但会遇到其他问题。请注意,重写的
INSERT... ON DUPLICATEUPDATE
查询在
VALUES
子句中具有数字文字,但是子句中仍然有一个
%s
占位符
UPDATE
。当它到达MySQL服务器时,将引发语法错误。

当我第一次测试您的示例代码时,我使用的是MySQLdb
1.2.3c1,无法重现您的问题。有趣的是,特定版本的软件包避免了这些问题的原因是正则表达式已损坏并且根本与语句不匹配。由于不匹配,因此

executemany
不会尝试重写查询,而只是循环遍历您的参数
execute
重复调用。

该怎么办

首先,不要回去安装1.2.3c1来完成这项工作。您希望尽可能使用更新的代码。

您可以移至另一个软件包,如在链接的“问答”中未曾建议的那样,但这将涉及一些调整,并且可能需要更改其他代码。

我建议改用一种更直接的方式来重写查询,并利用子句中的

VALUES()
功能
UPDATE
。通过此函数,您 可以
按列名引用在没有重复键冲突的情况下要插入的值(示例在MySQL文档中)。

考虑到这一点,这是一种实现方法:

dData = [[u'Daniel', u'00-50-56-C0-00-12', u'Daniel']]  # exact input you gavesql = """INSERT INTO app_network_white_black_list  (biz_id, shop_id, type, mac_phone, remarks, create_time)VALUES  (%s, %s, %s, %s, %s, NOW())ON DUPLICATE KEY UPDATE  type=VALUES(type), remarks=VALUES(remarks), create_time=VALUES(create_time);"""  # keep parameters in one part of the statement# generator expression takes care of the repeated valuescur.executemany(sql, ((bsid, shop_id, dType, mac, rem) for mac, rem in dData))

这种方法应该起作用,因为该

UPDATE
子句中没有参数,这意味着MySQLdb将能够成功地将带有参数的单行插入模板转换为具有文字值的多行插入语句。

注意事项:

  • 您不必提供元组
    executemany
    ;任何迭代都可以。
  • 与隐式连接的字符串相比,多行字符串使Python代码中的SQL语句可读性更高。当您将语句与字符串定界符分开时,很容易快速抓取该语句并将其复制到客户端应用程序中进行测试。
  • 如果要参数化部分查询,为什么不参数化所有查询?即使仅一部分是用户输入,以相同的方式处理所有输入值也更具可读性和可维护性。
  • 就是说,我没有参数化
    NOW()
    。我在这里的首选方法是将它
    CURRENT_TIMESTAMP
    用作列的默认值,并
    DEFAULT
    在语句中加以利用。其他人可能更喜欢在应用程序中生成此值并将其作为参数提供。如果您不担心版本兼容性,则可以保持原样。
  • 如果您无法避免在
    UPDATE
    子句中使用参数占位符(例如,由于
    UPDATE
    不能在语句中对值进行硬编码或从
    VALUES
    元组派生出值),则必须进行迭代
    execute
    而不是使用
    executemany


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/669242.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号