named_scope + average приводит к тому, что таблица будет указана более одного раза в запросе sql, запущенном на postgresql - PullRequest
1 голос
/ 15 мая 2010

У меня есть такие именованные области видимости ...

  named_scope :gender, lambda { |gender| { :joins => {:survey_session => :profile }, :conditions => { :survey_sessions => { :profiles => { :gender => gender } } } } }

и когда я звоню, все работает нормально.

У меня также есть этот средний метод, который я называю ...

Answer.average(:rating, :include => {:survey_session => :profile}, :group => "profiles.career")

, который также отлично работает, если я так назову.

Однако, если бы я назвал это так ...

Answer.gender('m').average(:rating, :include => {:survey_session => :profile}, :group => "profiles.career")

Я получаю ...

ActiveRecord :: StatementInvalid: PGError: ОШИБКА: имя таблицы «профили» указано более одного раза : ВЫБЕРИТЕ avg ("answers" .rating) AS avg_rating, profiles.career AS profile_career FROM "отвечает" ВЛЕВО НАРУЖНОЕ СОЕДИНЕНИЕ ".id =" survey_sessions_answers ".profile_id INNER JOIN" survey_sessions "ON" survey_sessions ".id =" answers ".survey_session_id INNER JOIN" профили "ON" анкеты ".id =" survey_sessions ".profile_id ГДЕ (" анкеты "." пол "= E'm ') GROUP BY profiles.career

Который немного сложен для чтения, но говорит, что я включаю профили таблиц дважды.

Если бы я просто удалил включение из среднего, оно работает, но это не очень практично, потому что среднее фактически вызывается внутри метода, который проходит область действия. Так что иногда пол или среднее число могут быть вызваны друг с другом, и если один из них отсутствует, включите профиль, он не будет работать.

Так что либо мне нужно знать, как исправить эту очевидную ошибку в Rails, либо найти способ узнать, какие области были применены к объекту ActiveRecord :: NamedScope :: Scope, чтобы я мог проверить, были ли они применены а если нет, то добавьте для среднего.

1 Ответ

1 голос
/ 15 мая 2010

Похоже, ActiveRecord генерирует плохой SQL:

SELECT avg("answers".rating) AS avg_rating,
       profiles.career AS profiles_career
FROM "answers"
     LEFT OUTER JOIN "survey_sessions" survey_sessions_answers
                    ON "survey_sessions_answers".id = "answers".survey_session_id
     LEFT OUTER JOIN "profiles"
                     ON "profiles".id = "survey_sessions_answers".profile_id
     INNER JOIN "survey_sessions"
                ON "survey_sessions".id = "answers".survey_session_id
     INNER JOIN "profiles"
                ON "profiles".id = "survey_sessions".profile_id
WHERE ("profiles"."gender" = E'm')
GROUP BY profiles.career

Предположительно, он генерирует левые объединения как часть получения проецируемого свойства, а внутренние соединения как часть получения критериев: это не будет недействительным (просто неэффективным), если он назначит псевдонимы этим таблицам, но это т. Есть ли способ указать псевдоним из вашего приложения?

...