使用内连接Rails ActiveRecord查询

时间:2012-11-08 03:05:07

标签: sql ruby-on-rails ruby activerecord

我有两个表,我正在尝试使用。

进行内连接

一个是users表,主键是id

另一个表是bars,其中user_id是外键。 bars还有一个名为foo_id的列,其中food_idfoos表的外键。

我正在尝试将ActiveRecord查询放在一起,我可以选择在N天前或之前创建的所有用户,并且没有任何foos bars.foo_id等于特定ID。我尝试过这样的事情:

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

此查询字段超过30,000个结果,这是不正确的,导致Users表只有12,000行。

我到底错在了什么?

4 个答案:

答案 0 :(得分:2)

尝试使用此

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

答案 1 :(得分:1)

您的联接数学错误,并且会为每个用户+ foo组合创建行。这是完整连接的工作方式。这种滑动的原因是因为您实际上没有将条形表加入到用户表中。通常你必须加入一个条件,就像在你的情况下bars.user_id=users.id一样,这是一个好主意。

话虽如此,您想要做的是确定哪些用户符合条件,然后加载:

users = User.where('id IN (SELECT DISTINCT user_id FROM bars WHERE bars.foo_id!=?)', 5)

这个子选择,如果单独运行,应该只返回一个没有特定foo的用户列表。将此作为WHERE条件使用时,只应加载这些用户。

答案 2 :(得分:1)

这应该有效 -

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

它将生成以下sql -

 select distinct users.* from users 
 INNER JOIN bars on bars.user_id = user.id
 WHERE bars.foo_id != 5 and users.created_at <= '2012-09-19 10:59:54'

答案 3 :(得分:0)

因为你的连接会在每个满足where子句的用户/条形条件的结果集中产生一行:如果用户有5个条形,它将出现5次。

你不能只用一个独特的方法解决这个问题,因为它会选择可以实现连接的所有行:所有至少有1个条形的用户,其foo_id不是5而不是没有这些条形的所有用户< / p>

您可以使用左连接执行此操作:

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")

这会尝试将“坏”栏(foo_id = 5)加入用户。因为它是左连接,如果不存在这样的条,那么将在结果集中返回一行,并将bars表的所有列设置为null,然后可以对其进行过滤。在ON子句中使用条形(foo_id = 5)的条件非常重要,这样才能使连接完成,而不是在连接后进行过滤。