Джанго.Запрос к базе данных: отдельный для одного поля - PullRequest
3 голосов
/ 08 ноября 2011

У меня есть следующие поля и данные в БД:

FirstName     LastName    Date

John          Davis       10-10-2011
Joe           Gray        20-09-2011
Ann           Davis       03-04-2010
Ann           Bovis       01-04-2010

Как выбрать из БД 3 элемента с последней датой и уникальной фамилией со всеми другими полями, включенными в результат.Это означает, что если есть более одного элемента с LastName, Дэвис в результате должен быть только один с самой поздней датой.Даже не знаю, как это сделать на чистом SQL - а Django выглядит вообще невозможным.

EDIT1.SQL QUERY.

Я написал запрос на чистом SQL:

SELECT TOP 3 *
FROM peopleTable as a1
WHERE  (select count(*)FROM peopleTable as a2 where a2.LastName=a1.LastName and a2.Date > a1.Date)<=0
ORDER by Date desc

Полагаю, было бы лучше, если бы я использовал этот запрос в django просто как чистый SQL.

Ответы [ 3 ]

1 голос
/ 08 ноября 2011

см. Документы по агрегации

думаю, вы хотите что-то вроде

Item.objects.values("lastname").annotate(
    date=Max("date"), firstname=Max("firstname"
    ).order_by()

Вы должны объединять или группировать по всем полям, включенным в сводный запрос. в вашем случае вы хотите max (data) и group_by фамилия. Вы также должны выбрать агрегацию для имени, скажем, max

обратите внимание, что, похоже, есть ошибка postgres при агрегировании по charfields

1 голос
/ 08 ноября 2011

Вы можете сделать это:

последняя дата и уникальная фамилия

или

все остальные поля

но вы не можете сделать оба. Если вы хотите получить самую последнюю дату для фамилии Дэвис, какие другие поля должны быть получены, firstname = John или firstname = Ann?

Я догадываюсь , что вы хотите, чтобы результат выглядел так:

FirstName     LastName    Date

John          Davis       10-10-2011
Joe           Gray        20-09-2011
Ann           Bovis       01-04-2010

Куда исчезла строка с Энн Дэвис, потому что она не самая последняя Дэвис в таблице. Правильно?

В этом случае ваш сырой SQL выглядит примерно так:

SELECT FirstName, LastName, Date
FROM
Table T1
WHERE
NOT EXISTS (
SELECT * FROM Table T2 WHERE T2.LastName=T1.LastName AND T2.Date > T1.Date
)

Который вы можете написать в Django, используя опцию Item.objects.raw () . Вы также можете использовать extra(where=…)

0 голосов
/ 08 ноября 2011

Вы не можете сделать это с помощью запроса;это просто слишком много логики для SQL.Однако, основываясь на том факте, что ключи словаря уникальны, вы можете получить то, что хотите, с небольшой изобретательностью.

Сначала получите набор запросов, упорядоченный по дате по возрастанию .Это может показаться нелогичным, потому что вам нужна последняя дата, но это будет иметь смысл на следующих шагах:

qs = SomeModel.objects.order_by('date')

Далее, мы будем использовать это в понимании списка для создания (key, value) кортежей(в Python 3+ вы действительно можете понимать словарь, но поскольку не многие из тех, кого я знаю, используют Python 3+, я подробно описываю это так):

qs_list = [(item.last_name, item) for item in qs]

Наконец, мы конвертируем этосписок кортежей в словаре:

items = dict(qs_list)

Теперь у вас будет словарь, в котором каждый ключ last_name уникален.Так как ключи словаря должны быть уникальными, последним значением каждой дублируемой фамилии было то, которое фактически сделало его. Поскольку список был упорядочен по возрастанию даты, последнее значение было «последним».

Вы можетепреобразовать этот словарь обратно в прямой список или просто перебрать его как есть.Единственная загвоздка в том, что вы больше не имеете дело с QuerySet, поэтому вы не можете выполнять какие-либо дополнительные фильтры и т. Д. Просто помните об этом и выполняйте эти шаги в последнюю очередь после того, как вы полностью построите свой запрос.1018 * И, конечно, вы можете сделать это как один вкладыш, если вы так склонны:

items = dict([(item.last_name, item) for item in SomeModel.objects.order_by('date')])
...