与ORDER结合使用时DISTINCT的问题

时间:2012-02-06 04:16:08

标签: sql ruby-on-rails ruby-on-rails-3

我正在尝试建立一个网站,对特定事件中的一些运动员的表现进行排名 - 我之前发布了一个问题,该问题得到了一些好的答复,我现在可以通过我的代码找出关键问题。

我有2个模型 - AthleteResult(运动员有很多结果)

每位运动员可以为特定赛事记录一些时间,我想确定每位运动员最快的时间,并将这些最快的时间排在所有运动员之列。

我使用以下代码:

 <% @filtered_names = Result.where(:event_name => params[:justevent]).joins(:athlete).order('performance_time_hours ASC').order('performance_time_mins ASC').order('performance_time_secs ASC').order('performance_time_msecs ASC') %>

这成功地对所有运动员的所有结果进行了排名(即一名运动员可以根据他们记录的时间在不同的地方出现多次)。

我现在希望为每位运动员取出最佳成绩,并将其纳入排名。我可以使用以下方法选择与最佳结果相对应的时间:

 <% @currentathleteperformance = Result.where(:event_name => params[:justevent]).where(:athlete_id => filtered_name.athlete_id).order('performance_time_hours ASC').order('performance_time_mins ASC').order('performance_time_secs ASC').order('performance_time_msecs ASC').first() %>

但是,当我尝试识别@filtered_names中列出的不同运动员名字时,我的问题出现了。我尝试使用<% @filtered_names = @filtered_names.select('distinct athlete_id') %>,但这并不像我预期的那样,有时它会以错误的顺序排名。

我发现,因为它代表我的代码基本上寻找不同的运动员结果之间的差异,从小时时间开始到进展到分钟,秒和毫秒。一旦发现每个不同运动员的结果之间存在差异,它就会相应地命令它们。

例如,如果我有2名运动员:

Time for Athlete 1 = 0:0:10:5
Time for Athlete 2 = 0:0:10:3

这将产生命令,运动员2,运动员1

但是,如果我有:

Time for Athlete 1 = 0:0:10:5
Time for Athlete 2 = 0:0:10:3
Time for Athlete 2 = 0:1:11:5

然后命令为运动员1,运动员2,因为第一个差异在分钟数字,运动员2更慢......

任何人都可以建议一种解决此问题的方法,并且基本上在@filtered_names中删除第一次出现的每个名称时的条目(即将名称保持在它们首次出现在{{1}中的顺序中}

感谢您的时间

2 个答案:

答案 0 :(得分:1)

如果您使用的是Ruby 1.9.2+,则可以使用Array#uniq并传递一个指定如何确定唯一性的块。例如:

@unique_results = @filtered_names.uniq { |result| result.athlete_id }

每个运动员只能返回一个结果,并且一个结果应该是数组中的第一个结果,这反过来将是您已经订购结果的最快时间。

有一点需要注意:@filtered_names可能仍然是ActiveRecord::Relation,它有自己的#uniq方法。您可能首先需要调用#all来返回结果数组:

@unique_results = @filtered_names.all.uniq { ... }

答案 1 :(得分:0)

您应该使用DB来执行最大计算,而不是ruby代码。将新列添加到名为results的{​​{1}}表中,并在每次更改“结果”表时为其设置值。

total_time_in_msecs

现在您可以按如下方式编写查询:

class Result < ActiveRecord::Base

  before_save :init_data

  def init_data
    self.total_time_in_msecs = performance_time_hours * MSEC_IN_HOUR +       
                                performance_time_mins * MSEC_IN_MIN +  
                                performance_time_secs * MSEC_IN_SEC + 
                                performance_time_msecs
  end

  MSEC_IN_SEC  = 1000
  MSEC_IN_MIN  = 60 * MSEC_IN_SEC
  MSEC_IN_HOUR = 60 * MSEC_IN_MIN
end

写一个简单的助手来分解数字时间部分:

athletes = Athlete.joins(:results).
  select("athletes.id,athletes.name,max(results.total_time_in_msecs) best_time").
  where("results.event_name = ?", params[:justevent])
  group("athletes.id, athletes.name").
  orde("best_time DESC")


athletes.first.best_time # prints a number

在视图中使用帮助程序显示细分时间。