Джанго эквивалентно SQL-выражению? Кроме того, работа с RawQuerySets? - PullRequest
1 голос
/ 25 марта 2011

Я сталкиваюсь с не очень хорошо документированной головоломкой, в которой вам нужно одновременно GROUP BY и ORDER BY.

ПРАВКА, чтобы включить некоторые модели:

class Matchup(models.Model):
    player = models.ForeignKey(Player)
    opponent = models.ForeignKey(Player)
    score = models.IntegerField()
    match = models.ForeignKey(Match)

class Match(models.Model):
    game = models.CharField()

Я думаю, что я включил все важное.Я пытаюсь составить таблицу лидеров, где у каждого игрока может быть только одна запись.Поэтому мне нужно group_by Player и order_by ('- skill').Некоторое время я бездарно возился с () без хороших результатов.

После нескольких часов проб и ошибок я пришел к 90% решению, выполнив необработанный SQL:

SELECT * FROM (SELECT * FROM scores ORDER BY score DESC) AS temp_table GROUP BY user ORDER BY score DESC

Правда, я не совсем понимаю SQL (главным образом, зачем нужен второй ORDER BY?)

1) Это лучший способ?Я не мог возвратить правильные наборы результатов, используя Django ORM, но очень вероятно, что я просто делал плохую работу.

2) Я хотел бы отфильтровать далее по отношению к иностранному ключу (match.game, wantиметь высокие баллы за игру).Лучший способ при работе с rawqueryset?

1 Ответ

3 голосов
/ 25 марта 2011

Сначала примечание: в вашем примере first ORDER BY не обязательно.Они никогда не находятся в подвыборах, и фактически для меньшей СУБД это привело бы к ненужной операции упорядочения (хотя я думаю, что большинство игнорирует это ORDER BY). ( Edit : Строго говоря, это не 't true. Однако в большинстве случаев упорядочение таблиц не имеет значения и имеет значение только порядок ваших результатов. Ваш запрос на самом деле является интересным исключением)

Но то, что вы делаете, может быть выполненос Django ORM и не требует необработанного SQL.Ваш SQL в общем-то странный.По сути, вы можете переписать его следующим образом:

SELECT
    *
FROM
    scores
GROUP BY
    user
ORDER BY
    score DESC

Подвыбор на самом деле ничего не делает (упорядочение не имеет значения для исходных данных, только в выводе), поэтому он просто исчезает.

Так что в этом случае для части Django ORM вы можете просто использовать функции агрегирования , чтобы выполнить то, что вам нужно.

edit - так как вы указалив комментариях, что первый ORDER BY действительно оказывает влияние из-за побочного продукта использования SELECT * [1] без каких-либо агрегаций при GROUP ing, соответствующий SQL будет:

SELECT
    user
    ,MAX(score) AS high_score
FROM
    scores
GROUP BY
    user
ORDER BY
    MAX(score) DESC

И снова вы можете использовать функции агрегирования, упомянутые по ссылке выше, чтобы получить эквивалентные операторы ORM.Это выглядело бы примерно так:

User.objects.annotate(high_score=Max('scores__score')).order_by('high_score')

Предполагается, что у вас есть внешний ключ от Score до User (Django выяснит, как соединить эти два, чтобы получить соответствующее поле score от вашей Score модели).

[1] - Это также подчеркивает, почему не рекомендуется использовать SELECT * в реальном коде!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...