Сложный запрос ARel - PullRequest
       1

Сложный запрос ARel

1 голос
/ 27 мая 2011

У меня сложный запрос, который я не могу обернуть (используя 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

Я пытаюсь найти число ProfileAnswersдля двух контактов, имеющих одинаковый value для определенного ProfileQuestion.Другими словами:

Получите общее количество ответов профиля, на которые два контакта ответили с одинаковым значением для конкретного profile_question

Я не хочу делать несколькоЗапросы и фильтрация, поскольку я знаю, что это возможно только с Sql, я просто не знаю, как это сделатьравный, но я все еще не могу обернуть голову вокруг этого.Любая помощь с благодарностью.

Ответы [ 2 ]

1 голос
/ 27 мая 2011

Я думаю, что это подойдет:

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_id равно NOT 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

РЕДАКТИРОВАНИЕ для двух конкретных контактов (с идентификаторами id1 и id2).

Добавил 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 
0 голосов
/ 27 мая 2011

Вот как я это сделал, спасибо еще раз @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.

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