我有一个如下表所示的模型,
create table `mytable`
(
`person` varchar(10),
`groupname` int,
`age` int
);
Run Code Online (Sandbox Code Playgroud)
我想从每组中选出 2 个最年长的人。原始的 SQL 问题和答案在这里StackOverflow,有效的解决方案之一是
SELECT
person,
groupname,
age
FROM
(
SELECT
person,
groupname,
age,
@rn := IF(@prev = groupname, @rn + 1, 1) AS rn,
@prev := groupname
FROM mytable
JOIN (SELECT @prev := NULL, @rn := 0) AS vars
ORDER BY groupname, age DESC, person
) AS T1
WHERE rn <= 2
Run Code Online (Sandbox Code Playgroud)
您也可以在此处检查 SQL 输出以及SQLFIDLE
我只是想知道如何在 Django 视图中将这个查询实现为查询集。
具有类似输出的另一个 SQL 将具有窗口函数,该函数使用特定组名称中的行号来注释每一行,然后您将在子句中过滤小于或等于 2 的行号HAVING。
在撰写本文时,django不支持基于窗口函数结果的过滤,因此您需要在第一个查询中计算行并People在第二个查询中进行过滤。
以下代码基于类似的问题,但它实现了每个返回的行数限制group_name。
from django.db.models import F, When, Window
from django.db.models.functions import RowNumber
person_ids = {
pk
for pk, row_no_in_group in Person.objects.annotate(
row_no_in_group=Window(
expression=RowNumber(),
partition_by=[F('group_name')],
order_by=['group_name', F('age').desc(), 'person']
)
).values_list('id', 'row_no_in_group')
if row_no_in_group <= 2
}
filtered_persons = Person.objects.filter(id__in=person_ids)
Run Code Online (Sandbox Code Playgroud)
Person对于表的以下状态
>>> Person.objects.order_by('group_name', '-age', 'person').values_list('group_name', 'age', 'person')
<QuerySet [(1, 19, 'Brian'), (1, 17, 'Brett'), (1, 14, 'Teresa'), (1, 13, 'Sydney'), (2, 20, 'Daniel'), (2, 18, 'Maureen'), (2, 14, 'Vincent'), (2, 12, 'Carlos'), (2, 11, 'Kathleen'), (2, 11, 'Sandra')]>
Run Code Online (Sandbox Code Playgroud)
上面的查询返回
>>> filtered_persons.order_by('group_name', '-age', 'person').values_list('group_name', 'age', 'person')
<QuerySet [(1, 19, 'Brian'), (1, 17, 'Brett'), (2, 20, 'Daniel'), (2, 18, 'Maureen')]>
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1403 次 |
| 最近记录: |