2014-12-19 67 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')