活动记录中的Rails User.joins.not(..)



我想在一个sql查询中查询所有没有注释的用户?

型号:

class User < ActiveRecord::Base
  has_many :comments
end
class Comment < ActiveRecord::Base
  belongs_to :user
end

所以我想要相反的东西:

User.joins(:comments).group('users.id')

但不是这样的:(因为它生成两个查询)

User.where.not(id: Comment.pluck(:user_id))

也许是这样的?

User.joins.not(:comments).group('users.id')

感谢您的意见!

您可以使用:

User.includes(:comments).where.not(comments: { id: nil })

这将导致原始SQL看起来像:

SELECT DISTINCT `users`.`*` FROM `users` LEFT OUTER JOIN `comments` ON `comments`.`user_id` = `users`.`id` WHERE `comments`.`id` IS NULL

要通过子查询实现这一点,请参阅下面的答案。

旧答案

你可以做一些类似的事情

User.where.not(id: Comment.select(:user_id))

如果您想要一个单独的(尽管是嵌套的)查询。

否则,请检查http://guides.rubyonrails.org/active_record_querying.html#joining-用于使用外部联接的表。

如果您使用postgresql,您可以执行类似的操作

User.joins("LEFT join comments c on users.id = c.comment_id").
select("users.id").
group("users.id").
having("count(users.id) = 1")

这将生成此查询

select u.id from users u
LEFT join comments c 
on c.comment_id = u.id
group by u.id
having count(u.id) = 1

这个查询不是生成两个SQL(也不是嵌套SQL),上面的答案是这样的。

另一个简单的解决方案User.where("id NOT IN (?)", Comment.pluck(:user_id))

从Rails 6.1开始,您可以使用

User.where.missing(:comments)

https://edgeapi.rubyonrails.org/classes/ActiveRecord/QueryMethods/WhereChain.html#method-i-缺少

最新更新