Проблемы с DISTINCT при использовании вместе с ORDER - PullRequest
1 голос
/ 06 февраля 2012

Я пытаюсь создать сайт, который оценивает выступления для выбора спортсменов на определенном мероприятии. Ранее я уже публиковал вопрос, на который было получено несколько хороших ответов, которые позволили мне определить ключевую проблему с моим кодом в настоящее время.

У меня есть 2 модели - Athlete и Result (У спортсмена много результатов)

У каждого спортсмена может быть записано несколько раз для определенного события, я хочу определить самое быстрое время для каждого события.атлета и оцените это самое быстрое время среди всех атлетов.

Я использую следующий код:

 <% @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, вытаскивая каждое имя в первый раз, когда оно появляется (т.е. сохраняя имена в том порядке, в котором они сначалапоявляются в @filtered_names

Спасибо за ваше время

Ответы [ 2 ]

1 голос
/ 06 февраля 2012

Если вы используете 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 { ... }
0 голосов
/ 07 февраля 2012

Вы должны использовать БД для вычисления максимального значения, а не код рубина. Добавьте новый столбец в таблицу results с именем 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

Напишите простого помощника, чтобы разбить количество временных частей:

def human_time time_in_msecs

  "%d:%02d:%02d:%03d" %   
    [Result::MSEC_IN_HOUR, Result::MSEC_IN_MIN, 
        Result::MSEC_IN_SEC, 1 ].map do |interval|
      r = time_in_msecs/interval
      time_in_msecs = time_in_msecs % interval
      r
    end

end

Используйте помощника в ваших представлениях для отображения разбитого времени.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...