【问题标题】:Django filtering on Window functionsDjango 过滤窗口函数
【发布时间】:2018-02-24 23:22:15
【问题描述】:

我在 Django 中有两个模型,AB

每个A 都有几个Bs 分配给它,Bs 是有序的,这是通过一个字段B.order_index 完成的,对于任何A,它从零开始向上计数。

我想编写一个查询来检查是否有任何A,其中一些Bs 有间隙或有重复的order_index 值。

在 SQL 中,可以这样完成:

SELECT order_index, RANK() OVER(PARTITION BY a_id ORDER BY order_index ASC) - 1 AS rnk
WHERE rnk = order_index'

但是,当我在 Django 中使用此代码尝试此操作时:

B.objects.annotate(rank=RawSQL("RANK() OVER(PARTITION BY a_id ORDER BY order_index ASC) - 1", [])).filter(rank=F('order_index'))

我收到一条错误消息:

django.db.utils.ProgrammingError: window functions are not allowed in WHERE
LINE 1: ...- 1) AS "rank" FROM "main_b" WHERE (RANK() OVE...

在 SQL 中,通过将整个事物包装在子查询中并将 Where 子句应用于该子查询,这很容易解决。我怎样才能在 Django 中做同样的事情?

【问题讨论】:

标签: django django-models window-functions


【解决方案1】:

表达此类查询的一种可能解决方法是使用https://github.com/dimagi/django-cte

from django_cte import With

cte = With(
    B.objects.all().annotate(
        rank=Window(
            expression=Rank(),
            partition_by=F('a_id'),
            order_by=F('order_index').asc()
        )
    )
)

cte.join(B.objects.all(), id=cte.col.id).with_cte(cte).annotate(
    rank=cte.col.rank
).filter(
    rank=F('order_index')
)

【讨论】:

    【解决方案2】:

    我没有对此进行测试,但使用@Bobort 评论中提到的新窗口函数,您可以尝试这样的事情,它产生的 SQL 非常接近您想要的,除了“-1”

    from django.db.models import F
    from django.db.models.expressions import Window
    from django.db.models.functions import Rank
    
    B.objects.annotate(rank=Window(
        expression=Rank(),
        order_by=F('order_index').desc(),
        partition_by=[F('a_id')]))
    

    【讨论】:

    • 问题是问如何过滤rank
    猜你喜欢
    • 2019-01-02
    • 2018-06-09
    • 1970-01-01
    • 2021-09-13
    • 2013-07-20
    • 1970-01-01
    • 2018-07-19
    • 2011-06-29
    • 2020-06-17
    相关资源
    最近更新 更多