2010-07-19 4 views
0

У меня есть приложения, в которых хранятся оценки игроков для каждого турнира. Так что у меня много-ко-многим ассоциации:SQL: Получить выбранный индекс строки из запроса

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 участия получает свой родитель турнир, загружает все tournamentr официального участия в (заказанное rating desc) и получить собственный индекс внутри этой коллекции

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

player.participations.last.rank 

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

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

find_by_sql("select @row:[email protected]+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).

P.S. Я использую 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; 

ответ

1
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; 
+0

Спасибо, это полезно для меня :) –

1

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

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 
+0

Y, там была опечатка с ": игроки", спасибо. Также добавлено несколько деталей. – fantactuka

+0

Является ли «тур» и «турнир» тем же самым? Вы, кажется, используете их взаимозаменяемо. –

+0

отредактировал мой оригинальный ответ, так как вставка кода в комментарии не работает –

Смежные вопросы