Запрос Rails Active Record: ответы на вопросы, упорядоченные по дате ответа, а не дубликаты - PullRequest
3 голосов
/ 29 ноября 2010

Вопрос имеет много ответов.

Легко найти все вопросы, на которые даны ответы, и заказать их по новейшему ответу:

def self.answered
  joins(:answers).order('answers.created_at desc')
end

В контроллере, я бы сделал @ отвечено = вопрос.отвечено

Но это возвращает дубликаты записей, если на вопрос был дан ответ более одного раза.

С другой стороны, легко найти отдельные вопросы, на которые даны ответы, но только если я не попытаюсь упорядочить их по их ответам дата создания:

def self.answered
  joins(:answers).select("DISTINCT questions.title")
end

(Давайте просто предположим, что заголовки вопросов проверяются на уникальность, поэтому в результате получаются все уникальные записи).

Проблема:

Этот запрос не может быть упорядочен к дате ответа"create_at", потому что я выбрал только заголовок вопроса в своем операторе выбора SQL ...

def self.answered
  joins(:answers).select("DISTINCT questions.title").order('answers.created_at desc')
end

приводит к этой ошибке (я использую Postgres):

PGError: ERROR:  for SELECT DISTINCT, ORDER BY expressions must appear in select list

Я думаю, это означает, что он хочет видеть "answers.created_at" в этом операторе select DISTINCT.

Похоже, что это сработает, если я захочу заказать по questions.created_at, но это не то, что я хочу:

def self.answered
  joins(:answers).select("DISTINCT(questions.title), questions.created_at").order('questions.created_at desc')
end

Здесь мои базовые знания SQL заканчиваются. Как выбрать отдельные вопросы (только те, на которые есть ответы) и упорядочить их в порядке убывания к дате их последнего ответа create_at?

Я хотел бы написать это с помощью запросов Rails 3 Active Record, но прямой SQL подойдет. Я надеюсь, что кто-то может помочь.

Ответы [ 4 ]

1 голос
/ 19 декабря 2011

@ Ответ Антона был бы предпочтительным решением, если бы мы говорили о MySQL, но, как вы указали, он вызывает ошибки в PostgreSQL, поскольку PG немного более ограничен в своих функциях выбора / группировки.

Вот как мне удалось заставить его работать с PG:

def self.answered
 scoped.select("questions.title").group("questions.title").joins(:answers).having('MAX(answers.created_at) IS NOT NULL').order('MAX(answers.created_at) DESC')
end

Или, если вы хотите выбрать все строки ActiveRecord для вопросов, вы можете выбрать / группировать по каждому столбцу в questions:

def self.answered
 cols = self.column_names.collect{ |c| "#{table_name}.#{c}" }.join(',')
 scoped.select(cols).group(cols).joins(:answers).having('MAX(answers.created_at) IS NOT NULL').order('MAX(answers.created_at) DESC')
end
1 голос
/ 29 ноября 2010

Почему бы не использовать запись как:

def self.answered
  joins(:answers).order("answers.created_at DESC").group("questions.id")
end

Это будет именно то, почему вы хотите:)

0 голосов
/ 30 ноября 2010

Это может в конечном итоге стать немного более эффективным и расширяемым, и следует избегать проблем, при которых psql сталкивается с агрегатными функциями:

select questions.*, count(answers.id) as answer_count from questions join answers on answers.question_id=questions.id group by answers.question_id having answer_count > 0 order by answers.created_at desc

P.S. под «расширяемым» я имел в виду, что вы можете разделить его на структуру Arel, а затем разбить области видимости, например with_answers и ответить, чтобы выполнить свою грязную работу за кулисами, оставив при этом все остальное в чистоте и позволяя позже добавить больше областей. :)

ОБНОВЛЕНИЕ: просто опубликовать путь Arel:

scope :answered, select('questions.*, count(answers.id) as answer_count').joins('join answers on answers.question_id=questions.id').group('answers.question_id').having('answer_count > 0').order('answers.created_at desc')
0 голосов
/ 29 ноября 2010

Я могу написать решение SQL для него. Это будет выглядеть так:

select q.id "Qn-ID", q.question, q.created_at "Qn-CreatedAt", a.id "Ans-ID", a.answer, a.created_at "Ans-CreatedAt" from questions q, answers a where a.question_id = q.id and a.id in (select max(id) answer_id from answers group by question_id) order by "Ans-CreatedAt" desc

Надеюсь, это поможет!

...