2014-12-19 68 views
4

查询复杂要值的简单表格获得最大的价值,我可以写在Django以下查询:主键要求在Django

MyTable.objects.aggregate(Max('value')) 

生成的SQL是:'SELECT MAX("mytable"."value") AS "value__max" FROM "mytable"'

现在,如果我写使用原始查询管理器相同的SQL:

1. MyTable.objects.raw('SELECT max(value) FROM mytable') 

的Django引发错误InvalidQuery: Raw query must include the primary key。 Django文档中也提到了这一点:“只有一个字段不能被忽略 - 主键字段”。所以在添加id字段后,我也需要GROUP BY。新的查询变为:

2. MyTable.objects.raw('SELECT id, max(value) FROM mytable GROUP BY id') 

这已经不给我一个最大值,因为我被迫使用GROUP BY id。现在我需要添加一个ORDER BYLIMIT语句来获得适用于其他简单的SQL语句的预期答案。

3. MyTable.objects.raw('SELECT id, max(value) AS mv FROM mytable GROUP BY id ORDER BY mv DESC LIMIT 1') 

有没有办法简化上面的查询,即不使用ORDER/LIMIT/GROUP BY(FWIW,使用PosgreSQL)?

更新:

下面是会工作黑客攻击。我将最大值别名为id,以使Django高兴。这里有什么问题吗?

MyTable.objects.raw('SELECT max(value) AS id FROM mytable') 

更新2:

这里有一个简单的SQL(1)VS复杂的最后一个(3)查询计划:

"Aggregate (cost=5.25..5.26 rows=1 width=2) (actual time=0.155..0.155 rows=1 loops=1)" 
" -> Seq Scan on mytable (cost=0.00..4.60 rows=260 width=2) (actual time=0.018..0.067 rows=260 loops=1)" 
"Total runtime: 0.222 ms" 


"Limit (cost=9.80..9.80 rows=1 width=6) (actual time=0.548..0.548 rows=1 loops=1)" 
" -> Sort (cost=9.80..10.45 rows=260 width=6) (actual time=0.545..0.545 rows=1 loops=1)" 
"  Sort Key: (max(value))" 
"  Sort Method: top-N heapsort Memory: 25kB" 
"  -> HashAggregate (cost=5.90..8.50 rows=260 width=6) (actual time=0.328..0.432 rows=260 loops=1)" 
"    -> Seq Scan on mytable (cost=0.00..4.60 rows=260 width=6) (actual time=0.018..0.069 rows=260 loops=1)" 
"Total runtime: 0.638 ms" 

PS的实际查询更为复杂(有点与此相关的答案:https://dba.stackexchange.com/a/86404/52114

+0

'GRO UP BY '(没有任何其他表加入)违背了汇总值的目的(即在你的例子中'max(value)'将只从最大值中选择1个值) - 'SELECT max(value)FROM mytable GROUP BY id LIMIT 1'与'SELECT max(value)FROM mytable'不一样 – pozs 2014-12-19 10:00:59

+0

你错过了'ORDER BY'子句。 1)&3)应该给出相同的结果,如果有一个单一的最大值。如果超过1,则需要添加id或其他内容以使订单可预测。 – user4150760 2014-12-19 12:30:43

+0

顺序无关紧要(它只能使您的查询可预测); 1)&3)不应该给你一般的结果,只有在特殊情况下:http://sqlfiddle.com/#!15/ceb1d/2 - 你也可以使用ORDER BY值DESC LIMIT 1'找到最大值,但在这种情况下,根本不需要聚合。 – pozs 2014-12-19 12:41:45

回答

9

您应该使用custom SQL代替Manager.raw()方法:

from django.db import connection 

cursor = connection.cursor() 
cursor.execute('SELECT max(value) FROM mytable') 
max_value = cursor.fetchone()[0] 
+0

我认为这是我可能最终采取的路线。我正在尝试一些解决方法,但'explain analyze'显示查询由于'id'需求而不必要地变得复杂。 – user4150760 2014-12-19 07:12:45

+1

@ user4150760试图控制ORM行为增加了另一层复杂性和不可预测性,这完全破坏了ORM的目的。 – 2014-12-19 07:36:37

+0

@ClodoaldoNeto你可否详细说一下'试图控制ORM的行为?是不是原生的SQL绕过ORM? – user4150760 2014-12-19 15:53:34

-1

我会做这样的事情:

select id, value from mytable order by value desc limit 1 
+0

你的意思是'按价值排序' – 2014-12-19 07:24:40

+0

和'limit 1' – 2014-12-19 07:26:34

+0

在合并@ClodoaldoNeto建议的更改之后,解释分析仍然表明它并不简单。 – user4150760 2014-12-19 07:31:20

0

ü可以使用

ModelName.objects.raw('SELECT 1 as id , max(value) FROM mytable')