2015-04-02 3 views
1

У меня проблема с оптимизацией SQL-запроса и использование активной записи для создания запроса. он включает в себя выбор идентификатора и счетчика ассоциации, а также условное соединение с переменным входом. Кроме того, я havent смог использовать оператор where, потому что мне нужны результаты, у которых пока нет ассоциаций. Мои модели являютсяАктивная запись, SQL: выбор и подсчет связи с условием объединения

class Vote < ActiveRecord::Base 
    belongs_to :user 
    belongs_to :venue 
    belongs_to :catering_event 
    validates :catering_event_id, uniqueness: { scope: :user_id } 
end 

class Venue < ActiveRecord::Base 
    has_many :votes 
    has_many :catering_events, through: :votes 
    has_many :users, through: :votes 
end 

class CateringEvent < ActiveRecord::Base 
    has_many :votes 
    has_many :venues, through: :votes 
    has_many :users, through: :votes 
end 

То, что я есть места, catering_events (события для краткости), и пользователи. пользователи могут набирать 1 голос за событие, где голосование является пользователем, выбирая место для мероприятия (user_id, place_id и catering_event_id).

На странице события шоу я хочу отобразить все места проведения и их подсчет голосов, в которых места без голосования подсчитывают количество голосов 0, которое я пытаюсь выполнить с помощью одного запроса. Я не мог использовать предложение where, потому что мои попытки отфильтровывали места, которые еще не голосовали.

В настоящее время у меня есть два функциональных решения, оба из которых я неудовлетворен. первый - это прямой запрос find_by_sql; однако я должен полу-взломать возвращаемые значения, потому что find_by_sql возвращает только атрибуты, которые имеет в настоящее время модель.

Для моих текущих данных:

#<Vote:0x007fb9f681ac38 id: 1, user_id: 2, venue_id: 3, catering_event_id: 1>, 
#<Vote:0x007fb9f681aa58 id: 2, user_id: 1, venue_id: 2, catering_event_id: 1>, 
#<Vote:0x007fb9f681a8f0 id: 3, user_id: 1, venue_id: 1, catering_event_id: 2> 

Моего функциональный find_by_sql запрос:

sql =  
"SELECT COUNT(votes.id) AS id, venues.id AS venue_id 
FROM venues 
LEFT OUTER JOIN votes ON votes.venue_id = venues.id 
AND votes.catering_event_id = ? 
LEFT OUTER JOIN catering_events ON catering_events.id = votes.catering_event_id 
GROUP BY venues.id" 

=> "SELECT COUNT(votes.id) AS id, venues.id AS venue_id FROM venues LEFT OUTER JOIN votes ON votes.venue_id = venues.id AND votes.catering_event_id = ? LEFT OUTER JOIN catering_events ON catering_events.id = votes.catering_event_id GROUP BY venues.id" 

pry(main)> Vote.find_by_sql [sql, '1'] 
Vote Load (9.0ms) SELECT COUNT(votes.id) AS id, venues.id AS venue_id FROM venues LEFT OUTER JOIN votes ON votes.venue_id = venues.id AND votes.catering_event_id = '1' LEFT OUTER JOIN catering_events ON catering_events.id = votes.catering_event_id GROUP BY venues.id 

=> [ 
    #<Vote:0x007fb9f33ca8c0 id: 0, venue_id: 1>, 
    #<Vote:0x007fb9f33ca668 id: 1, venue_id: 2>, 
    #<Vote:0x007fb9f33ca258 id: 1, venue_id: 3> 
] 

это возвращает все места и их votecounts для события питания 1. Однако, я должен назвать vote_count как некоторые атрибут на модели, из которой я вызываю find_by_sql, а так как голосование имеет 3 условия, нет модели 1, к которой я могу добавить атрибут votecount. когда я пытаюсь пространство имен счетчика для настраиваемого поля, я не получаю @attributes есть, как говорят документы, он просто опускает значение:

Vote Load (0.7ms) SELECT COUNT(votes.id) AS vote_count, venues.id AS venue_id 
FROM venues 
LEFT OUTER JOIN votes ON votes.venue_id = venues.id 
AND votes.catering_event_id = '1' 
LEFT OUTER JOIN catering_events ON catering_events.id = votes.catering_event_id 
GROUP BY venues.id 
=> [ 
    #<Vote:0x007fb9f31d29a0 id: nil, venue_id: 1>, 
    #<Vote:0x007fb9f31d2248 id: nil, venue_id: 2>, 
    #<Vote:0x007fb9f31d1c58 id: nil, venue_id: 3> 
] 

Второе решением я Нагуляв предполагает использование активной записи в сделать запрос, однако я гавань выяснили, как правильно дезинфицировать стыки заявление с переменной catering_event_id: (я не на самом деле запустить это на новых линиях, но для удобства чтения я разделить его)

Venue.select('venues.id as venue_id') 
    .joins('LEFT OUTER JOIN votes ON votes.venue_id = venues.id AND votes.catering_event_id = 2') 
    .joins('LEFT OUTER JOIN catering_events ON catering_events.id = votes.catering_event_id').group('venues.id') 
    .count('votes.id') 
(0.6ms) SELECT COUNT(votes.id) AS count_votes_id, venues.id AS venues_id FROM `venues` LEFT OUTER JOIN votes ON votes.venue_id = venues.id AND votes.catering_event_id = 2 LEFT OUTER JOIN catering_events ON catering_events.id = votes.catering_event_id GROUP BY venues.id 
=> {1=>1, 2=>0, 3=>0} 

Обратите внимание на первую joins statement, мне пришлось жестко кодировать 2 в:

AND votes.catering_event_id = 2 

as i havnt выяснил, как передать переменную в активную запись о соединениях.

В целом, я пытаюсь выполнить один запрос, используя либо прямой sql с помощью find_by_sql, либо активную запись (мои предпочтения относятся к активной записи), для выбора всех мест проведения и их подсчета голосов для переменной catering_event. Я бы предпочел изменить одно из моих текущих решений, чтобы либо позволить find_by_sql возвращать настраиваемые атрибуты с именами, либо определять, как правильно передать оператор объединения интерполированную/дезинфицированную переменную.

я на Rails 4.2.1 и 2.2.0 рубин

ответ

1

Ответ закончился тем, что в команде find_by_sql.

Хотя он не отображает его в возвращаемых значениях, виртуальный атрибут создается с использованием ключевого слова AS в запросе.Теперь я могу сделать SELECT COUNT(votes.id) AS vote_count, и хотя объекты возврата не показывают атрибут vote_count, они отвечают на него.

например.

query = Vote.find_by_sql([sql, '1']) 
query.map(&:vote_count) 
=> [0,1,1] 
Смежные вопросы