Rails Active Record查询:回答问题,按答复日期排序,不重复

时间:2010-11-29 05:49:25

标签: sql ruby-on-rails activerecord join distinct

一个问题有很多答案。

很容易找到所有已回答的问题,并按最新答案排序:

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

在控制器中,我会做@answered = Question.answered

但如果问题被多次回答,则会返回重复记录。

另一方面,很容易找到已经回答的不同问题,但前提是我没有尝试通过他们的答案 created_at日期来订购它们:

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

(我们假设这里的问题标题是唯一的,所以这会产生所有独特的记录。)

问题:

此查询无法按答案的“created_at”日期排序,因为我在SQL select语句中仅选择了问题的标题... < / p>

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

我想,这意味着它是否希望在选择DISTINCT语句中看到“answers.created_at”。

如果我想通过questions.created_at订购,以下情况会有效,但这不是我想要的:

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

这是我的基本SQL知识的用武之地。如何选择不同的问题(只有答案的问题)并按照最新答案的created_at日期按降序排列?

我想使用Rails 3 Active Record查询来编写它,但是直接的SQL很好。我希望有人可以提供帮助。

4 个答案:

答案 0 :(得分:1)

为什么不使用write as:

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

这将完全符合您的要求:)

答案 1 :(得分:1)

如果我们谈论MySQL,@ Anton的答案将是首选解决方案,但正如您所指出的,它会导致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

答案 2 :(得分:0)

我可以为它编写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

希望它有所帮助!

答案 3 :(得分:0)

这可能最终会更有效和可扩展,并且应该避免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')