Sql 使用内部联接的Rails ActiveRecord查询

Sql 使用内部联接的Rails ActiveRecord查询,sql,ruby-on-rails,ruby,activerecord,Sql,Ruby On Rails,Ruby,Activerecord,我有两个表,我正试图与它们进行内部联接 一个是users表,其中主键是id 另一个表是bar,其中user\u id是外键bar还有一个名为foo\u id的列,其中food\u id是foos表的外键 我正在尝试组合一个ActiveRecord查询,在这里我可以选择N天前或之前创建的所有用户,并且没有任何fooswherebar。foo\u id等于特定id。我尝试了这样做: users = User.where("users.created_at <= ?", 50.days.ago)

我有两个表,我正试图与它们进行内部联接

一个是
users
表,其中主键是
id

另一个表是
bar
,其中
user\u id
是外键
bar
还有一个名为
foo\u id
的列,其中
food\u id
foos
表的外键

我正在尝试组合一个ActiveRecord查询,在这里我可以选择N天前或之前创建的所有用户,并且没有任何
foos
where
bar。foo\u id
等于特定id。我尝试了这样做:

users = User.where("users.created_at <= ?", 50.days.ago).joins(:bars).where("bars.foo_id != 5")

users=User.where("users.created_at您的连接数学有误,它的效果是为每个用户+foo组合创建行。这就是完全连接的工作方式。出现此错误的原因是您实际上没有将bars表连接到users表。通常,您必须使用一个条件进行连接,如您的案例
bars.user_id=users.id
是个好主意

也就是说,您要做的是确定哪些用户符合条件,然后加载这些用户:

users = User.where('id IN (SELECT DISTINCT user_id FROM bars WHERE bars.foo_id!=?)', 5)
如果单独运行此子选择,则只应返回一个没有特定foo的用户列表。使用此选项作为
,其中
条件应仅加载这些用户。

尝试使用此选项

    User.includes(:bars).where("users.created_at <= ?", 50.days.ago).where("bars.foo_id != 5")
User.includes(:bar)。其中(“users.created_at这应该有效-

User.joins(:bars).where("bars.foo_id != ? and users.created_at <= ?", 5, 50.days.ago).select("distinct users.*")

User.joins(:bar).where(“bar.foo_id!=?和users.created_at因为它是您的联接,所以对于满足where子句的每个用户/bar条件,将导致结果集中的一行:如果用户有5个条,它将出现5次

您不能只使用一个distinct来解决这个问题,因为它将选择可以实现连接的所有行:所有至少有1个bar且foo_id不是5的用户,而不是所有没有此类bar的用户

您可以通过左连接执行此操作:

User.joins("left join bars on bars.user_id = users.id and bars.foo_id = 5").where("users.created_at < ? AND bars.id is null", 50.days.ago")
User.joins(“bar.User_id=users.id和bar.foo_id=5上的左连接条”)。其中(“users.created_at<?和bar.id为空”,50天以前)

这会尝试将“坏”条(foo_id=5)连接到用户。因为这是一个左连接,如果不存在这样的条,则结果集中会返回一行,其中bars表的所有列都设置为null,然后您可以对其进行筛选。重要的是在条上设置条件(foo_id=5)在ON子句中,使其有助于如何进行联接,而不是在联接后进行过滤。

它不是进行完全联接-如果存在名为:bar的关联,则使用适当的ON子句联接(:bar)该表(如果没有此类关联,则会引发错误)
User.joins("left join bars on bars.user_id = users.id and bars.foo_id = 5").where("users.created_at < ? AND bars.id is null", 50.days.ago")