我在将一些SQL转换为Django时遇到了麻烦。
想象一下,我们有一些汽车,每辆汽车都有一个独特的VIN,我们用其他一些数据记录它们在车间的日期。 (请忽略一个人可能以这种方式构建数据的原因。这是专门针对这个问题。:-))
class ShopVisit(models.Model):
vin = models.CharField(...)
date_in_shop = models.DateField(...)
mileage = models.DecimalField(...)
boolfield = models.BooleanField(...)
我们希望单个查询返回一个Queryset,其中包含每个vin
的最新记录并更新它!
special_vins = [...]
# Doesn't work
ShopVisit.objects.filter(vin__in=special_vins).annotate(max_date=Max('date_in_shop').filter(date_in_shop=F('max_date')).update(boolfield=True)
# Distinct doesn't work with update
ShopVisit.objects.filter(vin__in=special_vins).order_by('vin', '-date_in_shop).distinct('vin').update(boolfield=True)
是的,我可以遍历查询集。但这并不是非常有效,而且我需要很长时间来处理大约2M的记录。可以执行此操作的SQL如下(我认为!):
SELECT *
FROM cars
INNER JOIN (
SELECT MAX(dateInShop) as maxtime, vin
FROM cars
GROUP BY vin
) AS latest_record ON (cars.dateInShop= maxtime)
AND (latest_record.vin = cars.vin)
那么我怎么能用Django来实现呢?
答案 0 :(得分:1)
这有点未经测试,并且依赖于Django 1.11进行子查询,但可能类似于:
latest_visits = Subquery(ShopVisit.objects.filter(id=OuterRef('id')).order_by('-date_in_shop').values('id')[:1])
ShopVisit.objects.filter(id__in=latest_visits)
我有一个类似的模型,所以去测试它但得到了一个错误: “此版本的MySQL尚不支持'LIMIT& IN / ALL / ANY / SOME子查询”
它生成的SQL看起来很像你想要的,所以我觉得这个想法很合理。如果你使用PostGres,也许它支持那种类型的子查询。
这是它生成的SQL(修剪了一些并用假的替换了实际名称):
SELECT `mymodel_activity`.* FROM `mymodel_activity` WHERE `mymodel_activity`.`id` IN (SELECT U0.`id` FROM `mymodel_activity` U0 WHERE U0.`id` = (`mymodel_activity`.`id`) ORDER BY U0.`date_in_shop` DESC LIMIT 1)
答案 1 :(得分:0)
我想知道你是否自己找到了解决方案。
我只能提出原始查询字符串。 Django Raw SQL query Manual
UPDATE "yourapplabel_shopvisit"
SET boolfield = True WHERE date_in_shop
IN (SELECT MAX(date_in_shop) FROM "yourapplabel_shopvisit" GROUP BY vin);