查询集选择组的最新记录

Posted

技术标签:

【中文标题】查询集选择组的最新记录【英文标题】:Queryset select latest record for group 【发布时间】:2018-07-15 09:51:37 【问题描述】:

使用 Django 1.65 Python 3.4.1 甲骨文数据库

数据库“位置”中的表:

  location  | update_time     |  num_01   | num_02 | num_03 |
 -----------+-----------------+-----------+--------+--------
  B         | 06 Feb 18 04:14 |  42       | 43     |   55       
  C         | 22 Feb 17 04:14 |  77       | 99     |   23   
  A         | 05 Feb 18 04:14 |  48       | 43     |   21   
  A         | 01 Feb 18 04:14 |  82       | 83     |   74   

我想为每个位置选择具有最新 update_time 的行。

上表的结果应该是:

  location  | update_time     |  num_01   | num_02 | num_03 |
 -----------+-----------------+-----------+--------+--------
  A         | 05 Feb 18 04:14 |  48       | 43     |   21   
  B         | 06 Feb 18 04:14 |  42       | 43     |   55       
  C         | 22 Feb 17 04:14 |  77       | 99     |   23   

我可以使用查询集返回每个位置的最新更新时间:

latest_updates = Locations.objects.values('location').annotate(max_date=Max('update_time')).order_by('location')

但这只会在我查找整行时返回位置和最大更新时间 - num_01、num_02、num_03。

我花了很多时间搜索 ***,但没有什么适合的。 Oracle 似乎不支持我可以开始工作的排序方式和不同的选项。

由于某种原因,我无法导入子查询,所以这对我来说不是一个选择,我坚持使用这个版本的 django 等,因为它正在工作。

该表最终将包含合理数量的数据,因此如果可能,我正在寻找一个合理有效的解决方案。

【问题讨论】:

【参考方案1】:

你可以试试这个:

Locations.objects.order_by('location', '-update_time').distinct('location')

就我而言,它适用于 Django 2.1

【讨论】:

这对于 sqlite 来说效果不佳(我原以为测试的默认数据库引擎)会产生 NotImplementedError: DISTINCT ON fields is not supported by this database backend。使用无法跨不同支持的引擎移植的数据库抽象有点毫无意义。【参考方案2】:

对于 Django 1.11+,你也可以Subquery,所以这样的东西应该可以工作:

from django.db.models import Subquery, OuterRef, F

qs = Location.objects.all()

# make a subquery (filter, order, get 'id')
sq = qs.filter(location=OuterRef('location')).order_by('-update_time').values('id')

# use subquery in your query (via annotation + filter)
qs.annotate(latest=Subquery(sq[:1])).filter(id=F('latest'))

【讨论】:

【参考方案3】:

你应该使用,

latest_updates = Locations.objects.order_by('location', '-update_time').distinct('location')

【讨论】:

那只会返回整个表的最大更新时间?我想要每个营业地点组的最大 update_time。 "我想为每个位置选择具有最新 update_time 的行。" 我明白了。请检查我更新的答案。看看它是否适用于您的所有情况。 谢谢,那是关于 Oracle 不支持不同字段的部分。错误是:“此数据库后端不支持 DISTINCT ON 字段”。 :-/【参考方案4】:

我在这里找到的最佳解决方案:https://gist.github.com/ryanpitts/1304725

'''
given a Model with:

   category    = models.CharField(max_length=32, choices=CATEGORY_CHOICES)
   pubdate     = models.DateTimeField(default=datetime.now)
   <other fields>

Fetch the item from each category with the latest pubdate.

''' 

model_max_set = Model.objects.values('category').annotate(max_pubdate=Max('pubdate')).order_by()

q_statement = Q()
for pair in model_max_set:
    q_statement |= (Q(category__exact=pair['category']) & Q(pubdate=pair['max_pubdate']))

model_set = Model.objects.filter(q_statement)

【讨论】:

以上是关于查询集选择组的最新记录的主要内容,如果未能解决你的问题,请参考以下文章

带组的 Oracle 查询

复杂Rails Active Record查询选择具有真实结果的记录,以便当天最新更新其他创建的记录

将 HQL 与 MySQL 一起使用,如何在 group by 之前对结果集进行排序,以便选择正确的记录?

有重复组时选择最后一组的第一条记录

选择所有唯一元组的 SQL 查询

按名称选择每个记录组的最大值