我试图用Django的ORM进行此查询:
SELECT
id,
pn,
revision,
description
FROM (SELECT
id,
pn,
revision,
MAX(revision)
OVER (
PARTITION BY pn ) max_rev,
description
FROM table) maxarts
WHERE revision = max_rev
结果需要是一个查询集,我已经尝试过我所知道的Window / OuterRef / Subquery的每个组合都没有成功。 我必须使用原始查询吗?
提前致谢 马可
编辑#1:
我会尝试更好地解释,我有一个看起来像这样的模型:
class Article(models.Model):
pn = models.CharField()
revision = models.CharField()
description = models.CharField()
class Meta:
unique_together = [("pn", "revision"), ]
数据类似于:
pn1 rev1 description
pn1 rev2 description
pn2 rev1 anotherdescription
pn1 rev3 description
pn2 rev2 anotherdescription
我需要一个只包含Max(" revision")值的查询集,每次用户对该对象进行修改时,该值都会递增。 我希望现在更清楚了。谢谢!
编辑#2
如我所知,我正在写我已经尝试过的东西:
使用第一条消息中编写的查询的原始SQL,仅选择id字段并将其作为id__in = ids传递给ORM。地狱慢,无法使用。
声明了一个用作过滤器的WIndow函数:
Article.objects.annotate(max_rev=Window(expression=Max("revision"), partition_by=F("pn"))).filter(revision=F("max_rev"))
但是Django抱怨我不能在where子句中使用窗口函数(这是正确的)。
然后我试图将窗口用作子查询:
window_query = Article.objects.annotate(max_rev=Window(expression=Max("revision"), partition_by=F("pn")))
result = Article.objects.filter(revision= Subquery(window_query)
我也尝试使用OuterRef,使用max_rev注释作为连接,没有运气。 我没有想法!
答案 0 :(得分:0)
因此,每次针对文章进行修订时,都会在表格中创建一行?
如果是这样,您需要做的就是执行一个计数查询,该查询计算所有行并根据' pn'领域。如果您想使用Max
功能,那么我建议您更换“pn'包含IntegerField
或DecimalField
而非使用CharField
的字段。虽然取决于您的应用程序所处的位置,但这可能非常困难。
from django.db.models import Count
Article.objects.values('pn').annotate(maxvalues=Count('pn'))
答案 1 :(得分:0)
我认为通过使用 FirstValue 而不是 Max,您可以获得您想要的,与您拥有的没有太大区别:
>>> window_query = Article.objects.annotate(max_id=Window(
expression=FirstValue("id"),
partition_by=F("pn"),
order_by=F("revision").desc()
)).values("max_id")
>>> list(Article.objects.filter(id__in=Subquery(window_query)))
[<Article: Article object (4)>, <Article: Article object (5)>]
这会产生如下 SQL:SELECT * FROM articles_article WHERE id IN (SELECT FIRST_VALUE(id) OVER (PARTITION BY pn ORDER BY revision DESC) AS max_id FROM articles_article)
。
子查询表示按修订版本降序对窗口进行排序,按 pn 分区,并从每个分区中获取第一个 ID;然后我们在父查询中使用它来获取这些 ID 的相关文章。
在 PostgreSQL 上,你也可以这样做:
>>> Article.objects.order_by('pn', '-revision').distinct('pn')
<QuerySet [<Article: Article object (4)>, <Article: Article object (5)>]>
这会产生类似 SELECT DISTINCT ON (pn) * FROM articles_article ORDER BY pn ASC, revision DESC
的 SQL。