SQL: получить индекс выбранной строки из запроса - PullRequest
0 голосов
/ 19 июля 2010

У меня есть приложение, которое хранит рейтинги игроков для каждого турнира.Поэтому у меня есть ассоциация «многие ко многим»:

Tournament
  has_many :participations, :order => 'rating desc'
  has_many :players, :through => :participations

Participation
  belongs_to :tournament
  belongs_to :player

Player
  has_many :participations
  has_many :tournaments, :through => :participations

Модель участия имеет поле rating (с плавающей точкой), в котором хранится значение рейтинга (это как очки очков) для каждого игрока в каждом турнире.

То, что я хочу - получить последние 10 рангов игрока (rank - это позиция игрока в конкретном турнире, основанная на его рейтинге: чем больше рейтинг, тем выше рейтинг).Сейчас, чтобы получить рейтинг игрока в турнире, я загружаю все участия в этом турнире, сортирую их по полю rating и получаю индекс участия игрока с кодом рубина:

class Participation < ActiveRecord::Base

  belongs_to :player
  belongs_to :tournament

  def rank
    tournament.participations.index(self)
  end
end

Метод rankУчастник получает родительский турнир, загружает все участия в турнире (по заказу rating desc) и получает собственный индекс внутри этой коллекции

, а затем что-то вроде:

player.participations.last.rank

Одна вещь, которую яне нравится - он должен загрузить все участия в турнире, и в случае, если мне нужны рейтинги игроков для последних 10 турниров, он загружает более 5.000 предметов (и его количество будет расти с добавлением новых игроков).

Я считаю, что должен быть способ использовать SQL для него.На самом деле я пытался использовать переменные SQL:

find_by_sql("select @row:=@row+1 `rank`, p.* from participations p, (SELECT @row:=0) r where(p.tournament_id = #{tournament_id}) order by rating desc limit 10;")

Этот запрос выбирает топ-10 рейтингов данного турнира.Я пытался изменить его, чтобы выбрать последние 10 участников для данного пользователя и его звания.

Буду признателен за любую помощь.(Я думаю, что решением будет SQL-запрос, поскольку он довольно сложен для ActiveRecord).

PS Я использую rails3.0.0.beta4

UPD:

Вот окончательный SQL-запрос, который получает последние 10 рангов игрока (кроме того, он также загружает и участвующие турниры)

SELECT *, (
 SELECT COUNT(*) FROM participations AS p2 
  WHERE p2.tour_id = p1.tour_id AND p2.rating > p1.rating
 ) AS rank
 FROM participations AS p1 LEFT JOIN tours ON tours.id = p1.tour_id  WHERE p1.player_id = 68 ORDER BY tours.date desc LIMIT 10;

Ответы [ 2 ]

1 голос
/ 23 июля 2010
SELECT *, (
 SELECT COUNT(*) FROM participations AS p2 
  WHERE p2.tour_id = p1.tour_id AND p2.rating > p1.rating
 ) AS rank
 FROM participations AS p1 LEFT JOIN tours ON tours.id = p1.tour_id  WHERE p1.player_id = 68 ORDER BY tours.date desc LIMIT 10;
1 голос
/ 19 июля 2010

Прежде всего, если это:

Participation
  belongs_to :tournament
  belongs_to :players

быть этим?

Participation
  belongs_to :tournament
  belongs_to :player

Т.е. единственный игрок после того, как принадлежат_

Я изо всех сил пытаюсь понять, что это делает:

class Participation
  def rank_at_tour(tour)
    tour.participations.index(self)
  end
end

Вы на самом деле недостаточно объясняете свою схему, чтобы ее было легко перепроектировать. Это делает следующее ...?

«Получить все участия в данном туре и вернуть позицию этого текущего участия в этом списке»? Это как вы рассчитываете ранг? Если да, то я согласен, что это выглядит очень замысловатым способом.

Делаете ли вы выше для десяти объектов участия, которые вы возвращаете игроку, а затем берете среднее? Что такое рейтинг? Это как-то связано с рангом? В принципе, можете ли вы объяснить свою схему немного подробнее, а затем пересказать, что вы хотите сделать?

EDIT

Я думаю, вам нужен более эффективный способ определения позиции. Есть один способ, который я мог бы придумать, не задумываясь, - получить нужную запись, а затем посчитать, сколько ее выше. Добавьте 1 к этому, и вы получите позицию. например,

class Participation
  def rank_at_tour(tour)
    tour.participations.count("rating > ?", self.rating) + 1
  end
end

Вы должны увидеть в своем файле журнала (например, во время экспериментов в консоли), что это просто делает запрос подсчета. Если у вас есть индекс в поле рейтинга (который у вас должен быть, если у вас его нет), тогда этот запрос будет выполняться очень быстро.

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

class Participation
  def rank
    self.tour.participations.count("rating > ?", self.rating) + 1
  end
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...