我在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中做同样的事情?
答案 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')]))