我正在使用带有两个参数的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]
答案 0 :(得分:2)
字符串替换的问题是things are not properly quoted, as they are in parameter substitution.也就是说,引用可能正在做一些你不期望的事情。有些事要尝试:
现在,您将ID列表作为字符串传递(storeRestrictStr
)。尝试将其作为列表传递。
安装Django Debug Toolbar并使用它来查看生成的实际SQL及其输出。
您还没有说过10个结果是否正确,22个结果是否有12个错误匹配,或者22个结果是否正确,10个结果是12个,或者介于两者之间。
< / LI>