想象一下,我们有Django ORM模型Meetup
,其定义如下:
class Meetup(models.Model):
language = models.CharField()
speaker = models.CharField()
date = models.DateField(auto_now=True)
我想使用单个查询来获取语言,演讲者和日期 每种语言的最新活动。
>>> Meetup.objects.create(language='python', speaker='mike')
<Meetup: Meetup object>
>>> Meetup.objects.create(language='python', speaker='ryan')
<Meetup: Meetup object>
>>> Meetup.objects.create(language='node', speaker='noah')
<Meetup: Meetup object>
>>> Meetup.objects.create(language='node', speaker='shawn')
<Meetup: Meetup object>
>>> Meetup.objects.values("language").annotate(latest_date=models.Max("date")).values("language", "speaker", "latest_date")
[
{'speaker': u'mike', 'language': u'python', 'latest_date': ...},
{'speaker': u'ryan', 'language': u'python', 'latest_date': ...},
{'speaker': u'noah', 'language': u'node', 'latest_date': ...},
{'speaker': u'shawn', 'language': u'node', 'latest_date': ...},
]
D'哦!我们正在接受最新的活动,但错误的分组!
好像我需要一种GROUP BY
language
但SELECT
的方法。
一组字段?
更新 - 这种查询似乎很容易在SQL中表达:
SELECT language, speaker, MAX(date)
FROM app_meetup
GROUP BY language;
我喜欢这样做而不使用Django的raw()
- 是否有可能?
更新2 - 经过大量搜索,似乎在SO上有类似的问题:
更新3 - 最后,在@ danihp的帮助下,你似乎做得最好 是两个查询。我使用了以下方法:
# Abuse the fact that the latest Meetup always has a higher PK to build
# a ValuesList of the latest Meetups grouped by "language".
latest_meetup_pks = (Meetup.objects.values("language")
.annotate(latest_pk=Max("pk"))
.values_list("latest_pk", flat=True))
# Use a second query to grab those latest Meetups!
Meetup.objects.filter(pk__in=latest_meetup_pks)
这个问题是我上一个问题的后续问题:
答案 0 :(得分:1)
这种查询易于解释但难以编写。如果这是SQL,我将建议您按照日期(desc)排序的语言按行排序超过分区的CTE过滤查询
但这不是SQL,这是django查询api。简单的方法是对每种语言进行查询:
languages = Meetup.objects.values("language", flat = True).distinct.order_by()
last_by_language = [ Meetup
.objects
.filter( language = l )
.latest( 'date' )
for l in languages
]
如果某种语言没有会议,则会崩溃。 另一种方法是获取每种语言的所有最大数据:
last_dates = ( Meetup
.objects
.values("language")
.annotate(ldate=models.Max("date"))
.order_by() )
q= reduce(lambda q,meetup:
q | ( Q( language = meetup["language"] ) & Q( date = meetup["ldate"] ) ),
last_dates, Q())
your_query = Meetup.objects.filter(q)
也许有人可以在没有原始sql的单个查询中解释如何执行此操作。
已编辑到期OP评论
您正在寻找:
"SELECT language, speaker, MAX(date) FROM app_meetup GROUP BY language"
并非所有rdbms都支持此表达式,因为未包含在select子句上的聚合函数中的所有字段都应出现在group by子句中。在您的情况下,speaker
在select子句上(没有聚合函数),但不会出现在group by中。
在mysql中,他们不保证显示结果speaker
与最大日期相匹配。因此,我们不会面临简单的查询。
引用MySQL docs:
在标准SQL中,包含GROUP BY子句的查询无法引用 选择列表中未分配的非聚合列 GROUP BY子句...... 但是,这主要适用于所有值 在GROUP BY中未命名的每个非聚合列中都是相同的 对于每个小组。
符合您要求的最接近的查询是:
Reults = ( Meetup
.objects
.values("language","speaker")
.annotate(ldate=models.Max("date"))
.order_by() )