0

我正在使用带有两个参数的 SQL 字符串对 Django 模型进行原始查询。令人头疼的是,如果我使用字符串替换来填充参数,我会得到比使用参数替换更多的结果。在后一种情况下,结果是正确的,只是不完整。代码如下所示,唯一的变化是我省略了确切的 SQL:

# I have a long and ornate SQL statement that looks basically like this.
sql = "SELECT blah blah WHERE something = %s AND something_else in (%s)"

# If I do a raw query with string substitution I get more results (22) ...      
sqlInsecureFilled = sql % (divID, storeRestrictStr)
promos_insecured = Promotions.objects.raw(sqlInsecureFilled)

# ... than if I use a parameterized raw query, which produces (10)
promos_secure = Promotions.objects.raw(sql, [divID, storeRestrictStr])

但它变得更奇怪了。如果我从命令行执行此操作,从 raw_query 对象(即 promos_secure.query)中获取 SQL 并将其复制到 Sequel Pro 终端,那么两个查询都会产生相同数量的结果——22!但是:

In [35]: [len(list(promos_insecured)), len(list(promos_secure))]
Out[35]: [22, 10]

总结一下:查询似乎是相同的(它相当长,所以很难准确判断),并且当 promos_xx.query 字符串被复制到 MySQL 终端时,它们会产生完整的结果集。然而,当如上所示执行时,参数化版本返回 10 个结果,而另一个版本返回完整的 22 个结果。

为了完整起见,这里是 promos_secure.query (promos_insecured 是一样的):

SELECT DISTINCT promotion_id, promotion_name, promotion_up_date, promotion_down_date, promotion_asset_id, promotion_notes, promotion_promo_id FROM promotions, promo_detail WHERE promotion_id = promo_detail_promotion_id AND promotion_start_date < now() AND promotion_end_date > now() AND promo_detail_cust_division_id = 1 AND promo_detail_not_expired = 1 AND promo_detail_store_id in (8214, 8217, 4952, 8194, 8198, 8162, 5010, 5011, 5012, 8219, 8182, 5048, 5076, 5095, 5096, 5102, 5109, 5131, 5156, 5160, 5161, 5165, 5166, 5173, 5182, 5198, 5200, 5201, 5202, 5203, 5227, 5228, 5229, 5230, 5232, 5233, 5234, <bunch of other comma-separated numbers omitted>, 9281) ORDER BY promotion_end_date ASC

编辑:也许这是展示正在发生的事情以及为什么它很奇怪的最简洁的方式:

promo_u = promotions.models.Promotions.objects.raw(sql % (1, storeRestrictStr))
promo_s = promotions.models.Promotions.objects.raw(sql, (1, storeRestrictStr))

pid_u = [s.promotion_id for s in promo_u]
pid_s = [s.promotion_id for s in promo_s]

In [76]: [len(list(pid_u)), len(list(pid_s))]
Out[76]: [22, 10]

# You can see the smaller number of results is a subset of the larger.
In [77]: [pid in pid_u for pid in pid_s]
Out[77]: [True, True, True, True, True, True, True, True, True, True]

# The larger number results shows no obvious pattern as to why they're missing.
In [87]: [pid in pid_s for pid in pid_u]
Out[87]: [False, False, False, False, True, False, False, False, True, True, True, True,
          True, False, True, False, False, True, False, True, False, True]
4

1 回答 1

2

字符串替换的问题是没有正确引用,因为它们在参数替换中。也就是说,引用可能会做一些你意想不到的事情。一些事情要尝试:

  • 现在,您将 ID 列表作为字符串 ( storeRestrictStr) 传递。尝试将其作为列表传递。

  • 安装Django Debug Toolbar并使用它来查看正在生成的实际 SQL 及其输出。

  • 您还没有说这 10 个结果是否正确而 22 个结果是否有 12 个错误匹配,或者 22 个结果是否正确而 10 个结果是否缺少 12 个,或者介于两者之间。

于 2012-09-12T05:17:31.380 回答