计算多个属性的排名

时间:2013-05-30 21:12:07

标签: ruby-on-rails-3 postgresql

我正在构建赛车计时应用程序。随着汽车在赛道周围的比赛,用户将每个Car的分段时间输入到应用程序中。然后,应用程序会在每次拆分时对每辆车进行排名,并在我的视图中显示。

例如,Car A的split_1为5.00秒,split_2为15.00秒,split_3为25.00秒。 Car B的split_1为5.50秒,split_2为14.00秒,split_3为23.00秒。我在汽车A的视图中显示的等级是1,2,2。汽车B将是2,1,1。

我写了一个低效的,数据库密集型的方法来计算每个分割的等级。基本上,该方法为Timesheet上的每辆车获取所有split_1次,并将它们放入已排序的数组中,然后比较当前Car的split_1以找到其位置。它适用于每辆车和每一圈。这是一场噩梦。

class Car < ActiveRecord::Base
     has_many :laps
end

class Lap < ActiveRecord::Base
     belongs_to :car
     belongs_to :timesheet
end

class Timesheet < ActiveRecord::Base
     has_many :laps
end

我知道我错过了一种更简单,更有效的方法来计算每个等级。我正在使用Postgres 9.2,由于我的理解和经验有限,我认为窗口函数可能提供一个解决方案。还有另外一种方法吗?

1 个答案:

答案 0 :(得分:3)

使用如下表格:

CREATE TABLE split_times (car TEXT, split INT, "time" INTERVAL);
INSERT INTO split_times VALUES ('A', 1, '00:00:05');
INSERT INTO split_times VALUES ('A', 2, '00:00:15');
INSERT INTO split_times VALUES ('A', 3, '00:00:25');
INSERT INTO split_times VALUES ('B', 1, '00:00:05.5');
INSERT INTO split_times VALUES ('B', 2, '00:00:14');
INSERT INTO split_times VALUES ('B', 3, '00:00:23');
CREATE INDEX split_times_split_and_time ON split_times (split, "time");

这将为您提供拆分排名:

SELECT 
   car, split,
   RANK() OVER (PARTITION BY split ORDER BY time) AS rank 
FROM 
   split_times;

您可以使用它来获得每辆车的结果:

WITH x AS (
 SELECT 
    car, split, 
    RANK() OVER (PARTITION BY split ORDER BY time) AS rank 
 FROM
    split_times ORDER BY split
 )

SELECT 
   car, ARRAY_AGG(rank) AS ranks 
FROM
   x
GROUP BY car;

SQL Fiddle demo

窗口函数documentation