带 rails activerecord 的左外连接和 where 子句
Left outer join and where clause with rails activerecord
我有两个模型:User 和 Rsvp。用户有很多 Rsvps。
我想获取在指定日期没有创建 Rsvp 的所有用户。
所以我写了这个:
scope :free, -> (date) { joins(:rsvps).where.not(rsvps: {created_at: date.beginning_of_day..date.end_of_day}) }
但它仅在用户至少有一个 Rsvp 而不是 'date' 时才有效。当用户根本没有 Rsvp 时,它不起作用。
我尝试使用左外连接,但它不起作用。我一定错过了什么 :
scope :free, -> (date) { joins("LEFT OUTER JOIN rsvps ON rsvps.user_id = users.id").where.not(rsvps: {created_at: date.beginning_of_day..date.end_of_day}) }
这是我的单元测试:
it 'should fetch user if he has no rsvp at all' do
# Given
user = User.create!(email: 'm@m.com', password: '12345678', password_confirmation: '12345678')
# Then
expect(User.free(Date.new(2014, 1, 1)).count).to eq 1
end
通常 joins
returns 用户至少有一个 Rsvp。这就是为什么我建议使用 includes
。试试这个(可能你必须修改条件,因为我不确定它是否正是你想要的):
scope :free, -> (date) { includes(:rsvps).where('rsvps.created_at != ?', date ).references(:rsvps) }
你几乎做对了。您需要使用 GROUP_BY 语句,这样您就不会得到重复的行。
scope :free, -> (date) do
joins("LEFT OUTER JOIN rsvps ON rsvps.user_id = users.id")
.where.not(rsvps: {created_at: date.beginning_of_day..date.end_of_day})
.group("users.id") # or just .group(:id)
end
这应该有效:
scope :free, -> (date) { includes(:rsvps).where("rsvps.id IS NULL OR rsvps.created_at NOT BETWEEN ? AND ?", date.beginning_of_day, date.end_of_day).references(:rsvps) }
希望对您有所帮助!
我有两个模型:User 和 Rsvp。用户有很多 Rsvps。
我想获取在指定日期没有创建 Rsvp 的所有用户。
所以我写了这个:
scope :free, -> (date) { joins(:rsvps).where.not(rsvps: {created_at: date.beginning_of_day..date.end_of_day}) }
但它仅在用户至少有一个 Rsvp 而不是 'date' 时才有效。当用户根本没有 Rsvp 时,它不起作用。
我尝试使用左外连接,但它不起作用。我一定错过了什么 :
scope :free, -> (date) { joins("LEFT OUTER JOIN rsvps ON rsvps.user_id = users.id").where.not(rsvps: {created_at: date.beginning_of_day..date.end_of_day}) }
这是我的单元测试:
it 'should fetch user if he has no rsvp at all' do
# Given
user = User.create!(email: 'm@m.com', password: '12345678', password_confirmation: '12345678')
# Then
expect(User.free(Date.new(2014, 1, 1)).count).to eq 1
end
通常 joins
returns 用户至少有一个 Rsvp。这就是为什么我建议使用 includes
。试试这个(可能你必须修改条件,因为我不确定它是否正是你想要的):
scope :free, -> (date) { includes(:rsvps).where('rsvps.created_at != ?', date ).references(:rsvps) }
你几乎做对了。您需要使用 GROUP_BY 语句,这样您就不会得到重复的行。
scope :free, -> (date) do
joins("LEFT OUTER JOIN rsvps ON rsvps.user_id = users.id")
.where.not(rsvps: {created_at: date.beginning_of_day..date.end_of_day})
.group("users.id") # or just .group(:id)
end
这应该有效:
scope :free, -> (date) { includes(:rsvps).where("rsvps.id IS NULL OR rsvps.created_at NOT BETWEEN ? AND ?", date.beginning_of_day, date.end_of_day).references(:rsvps) }
希望对您有所帮助!