【问题标题】: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。

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

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

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

【问题讨论】:

    标签: python django oracle orm django-queryset


    【解决方案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)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-04-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多