Django ORM:window 具有后续过滤功能
Django ORM: window function with subsequent filtering
回答 , I found out window 函数不允许与 filter 组合(从技术上讲,它们是,但 filter 子句影响 window)。有提示将 window 函数包装在内部查询中,因此最终 SQL 看起来像这样(据我所知):
SELECT * FROM (
SELECT *, *window_function* FROM TABLE)
WHERE *filtering_conditions*
问题是:如何使用 Django ORM 编写此查询?
There are developers interested in solving it 但现在 ORM 无法做到这一点。
一个提议的解决方案是添加一个 QuerySet.subquery()
或 .wrap()
方法,该方法 推送 子查询中的查询集,以便随后对其进行过滤。
您需要使用原始查询。为了一次进行多个查询。了解更多信息 django documentation
for p in Person.objects.raw('''
SELECT * FROM (SELECT *, *window_function* FROM TABLE)
WHERE *filtering_conditions*'''):
print(p)
# John Smith
# Jane Jones
您还可以执行以下操作。
model.py
class Category(models.Model):
name = models.CharField(max_length=100)
class Hero(models.Model):
# ...
name = models.CharField(max_length=100)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
benevolence_factor = models.PositiveSmallIntegerField(
help_text="How benevolent this hero is?",
default=50
)
querySet.py
hero_qs = Hero.objects.filter(category=OuterRef("pk"))
.order_by("-benevolence_factor")
Category.objects.all()
.annotate(most_benevolent_hero=Subquery(hero_qs.values('name')[:1]))
生成的 SQL 看起来像这样..
SELECT "entities_category"."id",
"entities_category"."name",
(SELECT U0."name"
FROM "entities_hero" U0
WHERE U0."category_id" = ("entities_category"."id")
ORDER BY U0."benevolence_factor" DESC
LIMIT 1) AS "most_benevolent_hero"
FROM "entities_category"
另一个解决方案是通用 Table 表达式 (CTE),在 django-cte 的帮助下,您可以实现您想要的:
cte = With(
YouModel.objects.annotate(
your_window_function=Window(...),
)
)
qs = cte.queryset().with_cte(cte).filter(your_window_function='something')
大致翻译为:
WITH cte as (
SELECT *, WINDOW(...) as your_window_function
FROM yourmodel
)
SELECT *
FROM cte
WHERE cte.your_window_function = 'something'
回答
SELECT * FROM (
SELECT *, *window_function* FROM TABLE)
WHERE *filtering_conditions*
问题是:如何使用 Django ORM 编写此查询?
There are developers interested in solving it 但现在 ORM 无法做到这一点。
一个提议的解决方案是添加一个 QuerySet.subquery()
或 .wrap()
方法,该方法 推送 子查询中的查询集,以便随后对其进行过滤。
您需要使用原始查询。为了一次进行多个查询。了解更多信息 django documentation
for p in Person.objects.raw('''
SELECT * FROM (SELECT *, *window_function* FROM TABLE)
WHERE *filtering_conditions*'''):
print(p)
# John Smith
# Jane Jones
您还可以执行以下操作。
model.py
class Category(models.Model):
name = models.CharField(max_length=100)
class Hero(models.Model):
# ...
name = models.CharField(max_length=100)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
benevolence_factor = models.PositiveSmallIntegerField(
help_text="How benevolent this hero is?",
default=50
)
querySet.py
hero_qs = Hero.objects.filter(category=OuterRef("pk"))
.order_by("-benevolence_factor")
Category.objects.all()
.annotate(most_benevolent_hero=Subquery(hero_qs.values('name')[:1]))
生成的 SQL 看起来像这样..
SELECT "entities_category"."id",
"entities_category"."name",
(SELECT U0."name"
FROM "entities_hero" U0
WHERE U0."category_id" = ("entities_category"."id")
ORDER BY U0."benevolence_factor" DESC
LIMIT 1) AS "most_benevolent_hero"
FROM "entities_category"
另一个解决方案是通用 Table 表达式 (CTE),在 django-cte 的帮助下,您可以实现您想要的:
cte = With(
YouModel.objects.annotate(
your_window_function=Window(...),
)
)
qs = cte.queryset().with_cte(cte).filter(your_window_function='something')
大致翻译为:
WITH cte as (
SELECT *, WINDOW(...) as your_window_function
FROM yourmodel
)
SELECT *
FROM cte
WHERE cte.your_window_function = 'something'