如何在Rails中编写以下查询?

时间:2016-11-28 22:51:26

标签: sql ruby-on-rails ruby postgresql activerecord

我需要编写一个查询,该查询仅计算之前未参加过事件的个人。

以下是模型

class Individual < ActiveRecord::Base
  has_many :attendances, dependent: :destroy
  has_many :events, through: :attendances
end

class Attendance < ActiveRecord::Base
  belongs_to :event
  belongs_to :individual
end 

class Event < ActiveRecord::Base
  has_many :attendances, dependent: :destroy
  has_many :individuals, through: :attendances
end

在我看来,我有两个不同的查询。每个查询都会测量每个会计年度的事件参与情况。

查询2015财年:

  <%= Event.published.joins( :attendances => :individual ).where( 
  :events => {:fiscal_session => "2014-10-01".."2015-09-30"}
  ).distinct.count(:individual_id) %>

质疑2016财年:

  <%= Event.published.joins( :attendances => :individual ).where( 
  :events => { :fiscal_session => "2015-10-01".."2016-09-30"}
  ).distinct.count(:individual_id) %>

问题在于2016财年的查询不会忽视2015财年参加活动的个人。

我正在使用postgresql,并且我已经尝试编写范围和辅助方法来过滤2015年度参加的个人。但我还没有能够弄明白。

例如,2015财年:

<%= Individual.joins(attendances: :event).where( 
:events => {:fiscal_session => "2014-10-01".."2015-09-30"}
).group('individuals.id').having('count(attendances.id) > 0').count %>

结果是:

{2787=>1, 3469=>1} 

这是2016财年

<%= Individual.joins(attendances: :event).where( 
:events => {:fiscal_session => "2015-10-01".."2016-09-30"}
).group('individuals.id').having('count(attendances.id) > 0').count %>

结果如下:

{2905=>1, 3444=>1, 2787=>1, 2790=>1, 2858=>1} 

如您所见,individual_id 2787计算两次。我不想在2016财年的查询中计算2787

使用Rails和ActiveRecord实现所需计数的正确方法是什么?

3 个答案:

答案 0 :(得分:2)

我认为,实现目标的最佳方式是进行两次查询。

ignore_individuals = Event
.published
.joins(attendances: :individual)
.where( 
  'events.fiscal_session <= ?', '2015-09-30'
)
.pluck(:individual_id)

Event
.published
.joins(attendances: :individual)
.where.not(individual_id: ignore_individuals)
.where( 
  events: { fiscal_session: "2015-10-01".."2016-09-30" }
).distinct.count(:individual_id)

答案 1 :(得分:1)

我认为您正在寻找:Individual.includes(:events).where( events: { id: nil } ).count

这些人从未参加任何活动。

答案 2 :(得分:1)

不是积极的但是如果您正在寻找2016年参加过活动的个人数量,并且您的桌子上有时间戳,我相信您可以做到

Individual.joins(:attendances).where("attendances.created_at > ?", "01-01-2016").count