Требование первичного ключа в сыром SQL усложняет запрос в 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:

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 BY и LIMIT, чтобы получить ожидаемый ответ для другого простого оператора 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)?

Update:

Вот хак, который будет работать. Я имею в виду максимальное значение id, чтобы сделать Django счастливым. Есть ли здесь проблема?

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

Обновление 2:

Здесь план запросов для простого SQL (1) и сложный окончательный (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»

P.S.. Фактический запрос более сложный (несколько связанный с этим ответом: https://dba.stackexchange.com/a/86404/52114)

Лучший ответ:

Вы должны использовать пользовательский SQL вместо метода Manager.raw():

from django.db import connection cursor = connection.cursor() cursor.execute(‘SELECT max(value) FROM mytable’) max_value = cursor.fetchone()[0] Ответ №1

U может использовать

ModelName.objects.raw(‘SELECT 1 as id , max(value) FROM mytable’) Ответ №2

Я бы сделал что-то вроде:

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

Оцените статью
Добавить комментарий