我已经掌握了复杂排名功能所需的SQL。这是一项适用于赛车运动的应用,我需要根据条目Entry
对Timesheet
的{{1}}进行排名。
相关模型:
:total_time
条目class Timesheet
has_many :entries
end
class Entry
belongs_to :timesheet
belongs_to :athlete
end
class Run
belongs_to :entry
end
未存储在数据库中。它是:total time
的计算列。我使用Postgres(9.3)runs.sum(:finish)
函数来获取给定时间表的条目,并按此计算列对它们进行排名。
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
都会有相同的次数。有一个截止点(通常是前20但不总是)。这使得Postgres的rank()不准确,因为有些参赛作品比竞赛获胜者的Entry
更低,因为他们没有为第二次加热做出截止。
我的问题:是否可以在:total_time
内执行类似rank()
的操作,以生成如下所示的表格?或者还有另一种首选方式吗?谢谢!
注意:我将时间存储为整数,但为了清晰起见,我在下面的简化表中将它们格式化为更熟悉的MM:SS
rank()
答案 0 :(得分:0)
让我们创建一个表。 (养成在所有SQL问题中包含CREATE TABLE和INSERT语句的习惯。)
create table runs (
entry_id integer not null,
run_num integer not null
check (run_num between 1 and 3),
run_time interval not null
);
insert into runs values
(1, 1, '00:59.33'),
(2, 1, '00:59.93'),
(3, 1, '01:03.27'),
(1, 2, '00:59.88'),
(2, 2, '00:59.27');
此SQL语句将按您所需的顺序为您提供总计,但不对其进行排名。
with num_runs as (
select entry_id, count(*) as num_runs
from runs
group by entry_id
)
select r.entry_id, n.num_runs, sum(r.run_time) as total_time
from runs r
inner join num_runs n on n.entry_id = r.entry_id
group by r.entry_id, n.num_runs
order by num_runs desc, total_time asc
entry_id num_runs total_time -- 2 2 00:01:59.2 1 2 00:01:59.21 3 1 00:01:03.27
此语句添加了排名列。
with num_runs as (
select entry_id, count(*) as num_runs
from runs
group by entry_id
)
select
rank() over (order by num_runs desc, sum(r.run_time) asc),
r.entry_id, n.num_runs, sum(r.run_time) as total_time
from runs r
inner join num_runs n on n.entry_id = r.entry_id
group by r.entry_id, n.num_runs
order by rank asc
rank entry_id num_runs total_time -- 1 2 2 00:01:59.2 2 1 2 00:01:59.21 3 3 1 00:01:03.27