我对于复杂排名函数所需的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