【问题标题】:Django raw SQL query trouble with format characters and string interpolation带有格式字符和字符串插值的 Django 原始 SQL 查询问题
【发布时间】:2013-06-04 20:05:09
【问题描述】:

在我的 Django 应用程序中,我需要像这样生成一个 MySQL 查询:

SELECT * FROM player WHERE (myapp_player.sport_id = 4 AND (myapp_player.last_name LIKE 'smi%'))
UNION
SELECT * FROM player WHERE (myapp_player.sport_id = 4 AND (myapp_player.first_name LIKE 'smi%'));

我不能使用 Q 对象来 OR 一起 __istartswith 过滤器,因为 Django ORM 生成的查询不使用 UNION 并且它的运行速度至少比上面的 UNION 查询慢 40 倍。对于我的应用程序,这种性能是无法接受的。

所以我正在尝试这样的事情:

Player.objects.raw("SELECT * FROM myapp_player WHERE (sport_id = %%s AND (last_name LIKE '%%s%')) UNION SELECT * FROM sports_player WHERE (sport_id = %%s AND (first_name LIKE '%%s%'))", (sport.id, qword, sport.id, qword))

我为冗长的单行代码道歉,但我想在尝试调试此类问题时避免使用三引号字符串。

当我执行或 repr 这个查询集对象时,我得到如下异常:

*** ValueError: unsupported format character ''' (0x27) at index 133

这是单引号中的单引号,而不是三引号。如果我去掉 LIKE 子句周围的单引号,那么我会得到关于 LIKE 子句后面的 close-paren ) 字符的类似异常。

显然 Django 和 MySQL 在此查询的正确语法上存在分歧,但是否有适用于两者的语法?

最后,我也不确定用于字符串插值的 %%s 语法是否正确。 Django 文档建议我应该能够在 raw() 的参数中使用常规的 %s 语法,但是一些在线资源建议使用 %%s 或 ?作为原始 SQL 中字符串插值的占位符。

衷心感谢您对这个问题的一点点澄清!

【问题讨论】:

  • 在您的原始查询中,将sport_id = %%s 更改为sport_id = %s。我怀疑这会解决问题,但它是无效的语法
  • 我相信您必须转义 % 符号,因此您在查询中想要的每个百分号都应该是 first_name LIKE %%%s%% 另外使用 LIKE 查询不会扩展,我会研究全文索引为您的后端,或使用全文搜索引擎之一
  • @jsarets 试试这个dpaste.com/hold/1211374
  • 我不知道为什么您在使用 OR 时会出现性能下降。您是否针对 SELECT * FROM player WHERE (myapp_player.sport_id = 4 AND ((myapp_player.last_name LIKE 'smi%') OR (myapp_player.first_name LIKE 'smi%'))) 之类的查询测试过联合查询的性能?原始 SQL 确实应该是不得已而为之的功能。另外,您是否考虑将 index=True 添加到 first_name 和 last_name 列?如果你这样做,你会在这个查询上看到相当大的性能提升。

标签: mysql django union


【解决方案1】:

我让它像这样工作:

qword = word + '%'
Player.objects.raw("SELECT * FROM myapp_player WHERE (sport_id = %s AND (last_name LIKE %s)) UNION SELECT * FROM myapp_player WHERE (sport_id = %s AND (first_name LIKE %s))", (sport.id, qword, sport.id, qword))

除了 %s 似乎是参数化原始查询的正确方法之外,这里的关键是在调用 raw() 之前将 % 通配符添加到 LIKE 子句,并从 LIKE 子句周围排除单引号.即使 LIKE 子句周围没有引号,引号也会出现在最终发送到 MySQL 服务器的查询中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-11-07
    • 1970-01-01
    • 2014-05-21
    • 2021-03-12
    • 1970-01-01
    • 2021-10-07
    • 2011-09-04
    • 2011-12-05
    相关资源
    最近更新 更多