我有两个表,我正在尝试使用。
进行内连接一个是users
表,主键是id
。
另一个表是bars
,其中user_id
是外键。 bars
还有一个名为foo_id
的列,其中food_id
是foos
表的外键。
我正在尝试将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行。
我到底错在了什么?
答案 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)的条件非常重要,这样才能使连接完成,而不是在连接后进行过滤。