我在优化SQL查询时遇到问题,并利用活动记录来生成查询。它涉及选择关联的id和计数以及带有变量输入的条件连接。此外,我还没有能够使用where语句,因为我想要的结果还没有任何关联。 我的模型如下
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>
]
这将返回餐饮事件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}
注意第一个连接语句,我不得不硬编码2:
AND votes.catering_event_id = 2
因为我想知道如何将变量传递给活动记录连接语句。
总之,我正在尝试使用带有find_by_sql的直接sql或活动记录(我的偏好是有活动记录)执行单个查询,以选择所有场地,以及他们对变量catering_event的投票计数。我宁愿调整我当前的一个解决方案,要么允许find_by_sql返回自定义名称间隔属性,要么弄清楚如何正确传递连接语句和插值/清理变量。
我使用的是Rails 4.2.1和ruby 2.2.0
答案 0 :(得分:1)
答案最终出现在find_by_sql
命令中。
虽然它没有在返回值中显示它,但是使用查询中的AS
关键字创建虚拟属性。我现在可以SELECT COUNT(votes.id) AS vote_count
,虽然返回对象不显示属性vote_count
,但它们会对其进行响应。
e.g。
query = Vote.find_by_sql([sql, '1'])
query.map(&:vote_count)
=> [0,1,1]