复杂的ARel查询

时间:2011-05-26 21:31:17

标签: sql ruby activerecord

我有一个复杂的查询,我无法解决(使用sql或ActiveRecord)以下是我的模型:

class Contact
  has_many :profile_answers
end

class ProfileAnswer
  belongs_to :contact
  belongs_to :profile_question
end

class ProfileQuestion
  has_many :profile_answers
end

我正在尝试查找针对特定ProfileQuestion具有相同value的两个联系人的ProfileAnswers数。换句话说:

  

获取两个联系人使用相同值的特定profile_question回答的个人资料答案总数

我不想进行多次查询和过滤,因为我知道这只能用Sql实现,我只是不知道该怎么做

我曾考虑在profile_answersprofile_question_id进行自我加入,然后按value过滤相等,但我仍无法解决这个问题。非常感谢任何帮助。

2 个答案:

答案 0 :(得分:1)

我认为这样做:

SELECT COUNT(DISTINCT profile_question_id)
FROM 
  ( SELECT profile_question_id
    FROM ProfileAnswer an
      JOIN ProfileQuestion qu
        ON qu.id = an.profile_question_id
    WHERE contact_id IN ( id1, id2 )
    GROUP BY profile_question_id
           , value
    HAVING COUNT(*) = 2
  ) AS grp

似乎没有使用JOIN。因此,如果ProfileAnswer.profile_question_idNOT NULL,这就足够了:

SELECT COUNT(*)
FROM 
  ( SELECT profile_question_id
    FROM ProfileAnswer
    WHERE contact_id IN ( id1, id2 )
    GROUP BY profile_question_id
           , value
    HAVING COUNT(*) = 2
  ) AS grp

已针对两个特定联系人(包含ID id1id2)进行了编辑。

添加了WHERE并将COUNT (DINSTINCT )更改为COUNT(*)


也许这个带JOIN的版本可以更容易地适应ActiveRecord。

使用JOIN

SELECT COUNT(*)
FROM ProfileAnswer a
  JOIN ProfileAnswer b
    ON a.profile_question_id = b.profile_question_id
    AND a.value = b.value
WHERE a.contact_id = id1
  AND b.contact_id = id2 

答案 1 :(得分:0)

以下是我最终如何做到这一点,再次感谢@ypercube:

class ProfileAnswer < ActiveRecord::Base

  def self.for_contacts(*contacts)
   where :contact_id => contacts.collect(&:id)
  end

  def self.common_for_contacts(*contacts)
    select(:profile_question_id).for_contacts(*contacts).group(:profile_question_id, :value).having("count(*) = #{contacts.length}")
  end

  def self.common_count_for_contacts(*contacts)
    find_by_sql("select count(*) as answer_count from (#{common_for_contacts(*contacts).to_sql})").first.answer_count
  end
end

# Usage
ProfileAnswer.common_count_for_contacts(contact1, contact2[, contact3...])

最后仍然必须使用find_by_sql进行嵌套选择...不确定是否有任何解决方法?

同样烦人的是find_by_sql返回一个数组,所以我不得不使用.first然后给我一个具有answer_count属性的对象。