我對於複雜排名函數所需的SQL很感興趣。這是一款適用於賽車運動的應用程序,我需要根據條目的:total_time
對每個Entry
進行排名Timesheet
。SQL中使用Postgres進行復雜排名
相關機型:
class Timesheet
has_many :entries
end
class Entry
belongs_to :timesheet
belongs_to :athlete
end
class Run
belongs_to :entry
end
條目的:total time
不存儲在數據庫中。這是一個計算列runs.sum(:finish)
。我使用Postgres(9.3)rank()
函數獲取給定時間表的條目,並按計算出的列對它們進行排名。
def ranked_entries
Entry.find_by_sql([
"SELECT *, rank() OVER (ORDER BY total_time asc)
FROM(
SELECT Entries.id, Entries.timesheet_id, Entries.athlete_id,
SUM(Runs.finish) AS total_time
FROM Entries
INNER JOIN Runs ON (Entries.id = Runs.entry_id)
GROUP BY Entries.id) AS FinalRanks
WHERE timesheet_id = ?", self.id])
end
到目前爲止好。這會返回具有rank
屬性的我的輸入對象,我可以在timesheet#show
上顯示該屬性。
現在棘手的部分。在Timesheet
,並非每個Entry
將具有相同的運行次數。有一個截止點(通常是前20名,但並不總是)。這使得Postgres的rank()不準確,因爲一些參賽者比競賽獲勝者有更低的:total_time
,因爲他們沒有爲第二次高潮做出決定。
我的問題:是否有可能像做一個rank()
內的rank()
產生一個表,看起來像下面的一個?還是有另一種首選的方式?謝謝!
注:我店倍整數,但我格式化它們作爲比較熟悉MM:在簡化見下表SS爲清楚起見
| rank | entry_id | total_time |
|------|-----------|------------|
| 1 | 6 | 1:59.05 |
| 2 | 3 | 1:59.35 |
| 3 | 17 | 1:59.52 |
|......|...........|............|
| 20 | 13 | 56.56 | <- didn't make the top-20 cutoff, only has one run.
這聽起來像你不應該擺在首位來選擇所有行(所有運行?)。如果你選擇了正確的行 - 一個將排除所有隻有一次運行的條目的選擇 - 那麼rank()將返回你期望的結果。在你的問題的上下文中,我想我會說,首選的方法是選擇正確的行* first *,之後排名非常簡單。 – 2015-04-05 19:20:35
我選擇所有行,因爲我想包括在排名中只有一次運行的條目。無論運行次數如何,每個條目都需要進行排名。排名前20的球隊是根據total_time排名的,而21球隊的排名是他們首輪比賽的結束時間。 – jktress 2015-04-05 19:24:15
只需對平均值進行排名而不是總數呢? – 2015-04-05 19:45:27