2015-04-02 45 views
1

我有一個問題,優化SQL查詢,並利用活動記錄生成查詢。它涉及選擇關聯的id和計數,以及具有變量輸入的條件連接。此外,我還沒有能夠使用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,venue_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模型。當我嘗試命名空間中的計數的自定義字段,我沒有得到一個具有@屬性作爲文檔說,它只是省略了值:

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} 

通知第一加入發言,我只好硬編碼2:

AND votes.catering_event_id = 2 

我havnt想出如何一個變量傳遞給活動記錄加入聲明。

總之,我試圖使用find_by_sql或活動記錄(我的首選項是活動記錄)的直接sql執行單個查詢,選擇所有場所以及它們對變量catering_event的投票計數。我寧願調整當前的解決方案之一,以允許find_by_sql返回自定義的名稱間隔屬性,或者找出如何正確傳遞聯接語句和插值/清理變量。

我是on Rails的4.2.1和Ruby 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]