Django过滤Window函数

时间:2017-09-15 17:49:32

标签: django django-models window-functions

我在Django,A和B中有两个模型。

每个A都有几个B分配给它,并且Bs是有序的,这是用字段B.order_index完成的,该字段从任何A的零开始向上计数。

我想编写一个查询,检查是否存在任何A,其中某些B有间隙或重复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中做同样的事情?

2 个答案:

答案 0 :(得分:0)

表达这种查询的一种可能的解决方法是使用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')
)

答案 1 :(得分:-1)

我还没有测试过,但是使用@Bobort注释中提到的新的Window函数,您可以尝试这样的操作,它产生的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')]))