2010-07-19 37 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