我正在尝试将尽可能多的原始sql转换为使用django orm,但遇到了一个障碍。我正在尝试执行类似于此的查询:
SELECT table.x,
MAX(table.y) AS y,
table.group_category,
table.group_number,
FROM table
GROUP BY table.group_category, table.group_number
到目前为止,我一直在尝试的是这种排列:
q = MyModel.objects\
.filter(**filter_kwargs)\
.values('group_category', 'group_number')\
.annotate(y=Max('y'))\
.values('x','y','group_category','group_number')
然而,这似乎不起作用。如果我排除最后一个 values()
,它产生以下(大致):
SELECT MAX(table.y) AS y,
table.group_category,
table.group_number,
FROM table
GROUP BY table.group_category, table.group_number
它不选择 table.x
. 但如果我包括最后一个 values()
...
SELECT table.x,
MAX(table.y) AS y,
table.group_category,
table.group_number,
FROM table
GROUP BY x, y, table.group_category, table.group_number
it分组依据 x, y
. 所以很明显,所有的值都被替换了,annotate使用queryset给定的任何值(因为它的计算是惰性的?)。关于聚合和值的文档似乎表明,按此顺序执行这两个值函数将产生预期效果,我发现一个writeup(2013年)也表明了这一点。我做错什么了吗?这在django orm中仍然可能吗?有没有什么方法可以不使用extra()或原始sql来实现这一点?为了演示的目的,我尽量使这个例子保持简单,但是我的实际问题涉及到一个连接。这会让事情复杂化吗?
更新1
我能够找到它,但是,它仍然不能产生我想要的最佳版本的sql查询。为了得到所需的结果,我改为执行一个查询 MAX(table.y)
,然后使用 __in
对子查询的值。子查询执行分组。
filtered = MyModel.objects.filter(**filter_kwargs)
subq = filtered\
.values('group_category', 'group_number')\
.annotate(y=Max('y'))\
.values_list('y', flat=True)
q = filtered\
.filter(y__in=subq)\
.values('x','y','group_category','group_number')
正如我所说的,这样做可以让我得到我需要的结果。问题是,它比只选择不同于groupby的查询要慢得多,因为它创建了一个相对庞大的子查询。我现在还没有将此标记为答案,因为它仍然无法生成与我真正想要的匹配的查询。相反,它看起来像这样:
SELECT table.x,
table.y,
table.group_category,
table.group_number,
FROM table
WHERE y IN
(SELECT MAX(U0.y) AS y
FROM table U0
GROUP BY U0.group_category, U0.group_number)
此外,看起来我甚至不能使用extra(),因为它类似地只向select子句添加已经是queryset的一部分的列,即。 values()
.
更新2
结果证明,我的凌乱解决方法不起作用,因为它获取所有y(1行)的最大值并返回它,而不是将它们按组\类别和组\编号分组并使用 MAX
他们的 y
是的,所以我回到绘图板上。
1条答案
按热度按时间camsedfj1#
您似乎想要的是计算最大值,但返回所有行而不进行任何分组。这就是窗口函数的用途(可从django 2.0获得):
但是为什么你的方法
GROUP BY
工作?在原始查询中,原因django(和数据库;您引用的sql将引发语法错误)坚持按
x
如果你分组的话category
以及number
,您可能有几个x
一个分组行的值category
以及number
. db应该选择哪一个?它不能为你做出这样的选择。如果
x
不重要,你可以忽略它。如果它很重要,但对于一组category
以及number
,然后按x
不会伤害你。如果有不同的x
值,并且它们很重要,您需要决定选择哪一个(并相应地告诉db)。同样的道理y
.