给定模型
class Entity(models.Model):
identifier = models.IntegerField()
created = models.IntegerField()
content = models.IntegerField()
class Meta:
unique_together = (('identifier', 'created'))
我想在常见created
的对象中查询identifier
最大的所有对象。
在SQL中,子查询中的窗口函数解决了这个问题:
SELECT identifier, content
FROM entity
WHERE (identifier, created)
IN (SELECT identifier, max(created) OVER (PARTITION BY identifier)
FROM entity);
另请参阅:http://sqlfiddle.com/#!17/c541f/1/0
Django 2.0中都提供了窗口函数和子查询。但是,我还没有找到一种方法来表达具有多列的子查询表达式。
有没有办法将SQL查询转换为Django QuerySet世界?这可能是一个XY问题,我的问题可以用不同的方式解决吗?
我丑陋的解决方法是
Entity.objects.raw('''
SELECT * FROM app_entity e
WHERE e.created = (SELECT max(f.created) FROM app_entity f WHERE e.identifier = f.identifier)''')
因为底层的sqlite3版本显然无法处理多列子查询。
答案 0 :(得分:1)
Postgres specific version 效果很好,但不能很好地与必须在崩溃之前/之后发生的过滤结合起来。也不能下单。
我所做的是在子查询中使用它:
class LatestQuerySet(models.QuerySet):
def latest_objects(self):
# Get the latest version of every object matching the current query
latest = (
self
# Sort by identifier with latest version first
.order_by("identifier", "-created")
# This only works on Postgres
.distinct("identifier")
)
# Return a new queryset that includes the subquery
return self.filter(id__in=latest)
然后可以这样组合:
# Find the latest version of every object that is at least staged for publication
# and check whether that object should be published in its latest version.
Entity.objects\
.filter(state__gte=STAGED_FOR_PUBLISH)\
.latest_objects()\
.filter(include_entity=True)
答案 1 :(得分:0)
我认为您可以用另一种方式来做(但是我不确定它的表现是否会好于窗口表达式)
created
这将获取给定identifier
的最大.annotate(max_created=Subquery(created)).filter(created=F('max_created'))
值,作为相关子查询,然后仅过滤匹配的那些子查询。
这可能需要调整:我不确定是否可以像这样对子查询进行过滤,或者是否需要DISTINCT ON
或类似的其他可怕内容。
此外,如果您使用的是Postgres,则可以使用Entity.objects.order_by('identifier', '-created').distinct('identifier')
功能来获得一个真正整洁的解决方案:
#!/usr/bin/expect
set yest [ exec /bin/date -d "yesterday" +%Y%m%d]
send_user $yest
exit 1