2010-07-19 143 views
0

我有一个应用程序,用于存储每个锦标赛的玩家评分。所以我有很多-to-many关联: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场对它们进行排序,并与Ruby代码得到了玩家的参与指数:

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场比赛的球员排名,它会加载超过5000个项目(当新球员加入时它的数量会增加)。

我相信应该有办法为它使用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

谢谢,这对我有用:) – 2013-07-25 06:42:11

1

首先,应该这样:

Participation 
    belongs_to :tournament 
    belongs_to :players 

是这样?

Participation 
    belongs_to :tournament 
    belongs_to :player 

即,belongs_to后的单数球员?

我努力让我的头围绕这是什么做的:

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

你真的不解释足够了解你的架构,使其容易进行逆向工程。它做了以下...?

“获取给定参观的所有参与并返回当前参与该列表的位置”?这是你如何计算等级?如果是这样,我同意这似乎是一个非常复杂的做法。

你是否为上述十个参与对象做出回应,然后取其平均值?什么是评级?这与排名有什么关系?基本上,你能否更详细地解释你的模式,然后重申你想要做的事情?

编辑

我想你只需要找到位置的更有效的方法。有一种方法可以考虑我的头顶 - 得到你想要的记录,然后计算它上面有多少记录。加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 2010-07-19 15:54:40

+0

'巡回赛'和'锦标赛'是一回事吗?你似乎可以互换使用它们。 – 2010-07-20 09:12:08

+0

编辑了我的原始答案,因为将代码粘贴到评论中并不真正起作用 – 2010-07-20 10:03:29