ActiveRecord在执行子查询时缺少连接表

时间:2017-08-08 08:52:31

标签: ruby-on-rails

在Rails中使用带有连接的子查询时,我遇到了奇怪的行为。虽然生成非子查询工作正常,但Rails在构造完整查询时似乎“忘记”了连接表。

这是一个例子。请不要过多关注我使用的表,这只是一个例子,因为我使用的实际查询有点过于复杂。

这个有效:

2.4.0 :015 > User.all.includes(:company).where(companies: {id: 0})
  SQL (0.5ms)  SELECT `users`.`id` AS t0_r0, [..]
    `companies`.`id` AS t1_r0, [..]
    FROM `users` LEFT OUTER JOIN `companies` ON `companies`.`id` =
    `users`.`company_id` WHERE `companies`.`id` = 0 ORDER BY
    `users`.`username` ASC
=> #<ActiveRecord::Relation []> 

但是当我把它全部包裹在一个地方时:

2.4.0 :016 > User.where(id: User.all.includes(:company).where(
companies: {id: 0}).references(:companies))
  User Load (1.3ms)  SELECT `users`.* FROM `users` WHERE `users`.`id`
    IN (SELECT `users`.`id` FROM `users` WHERE `companies`.`id` = 0 ORDER
    BY `users`.`username` ASC) ORDER BY `users`.`username` ASC
ActiveRecord::StatementInvalid: Mysql2::Error: Unknown column
'companies.id' in 'where clause'

有什么明显的东西我不见了吗?或者Rails可以不处理子查询中的连接?

另外,我不能使用joins()。我还需要返回连接不会产生任何结果的记录,因此需要包含()。

我使用的是Ruby 2.4.0和Rails 5.0.2。

2 个答案:

答案 0 :(得分:1)

您可以尝试使用left_outer_joins,因为这似乎是使用includes在这种情况下为您购买的内容(此处为User has_many :ordersOrder belongs_to :user):

puts Order.where({
  id: Order.left_outer_joins(:user).where(users: { id: [nil, 1] })
}).to_sql

# SELECT "orders".* FROM "orders"
# WHERE "orders"."id" IN (
#   SELECT "orders"."id" FROM "orders"
#   LEFT OUTER JOIN "users" ON "users"."id" = "orders"."user_id"
#   WHERE ("users"."id" = 1 OR "users"."id" IS NULL)
# )

这是可能的(虽然我现在只是猜测)Rails是一种自我优化的方式。只需要LEFT OUTER JOINS才能从{{中选择所有列1}},但由于您已将其添加到条件中,因此不再需要抓取所有列,只需抓取Company,因此它不会进行连接。

答案 1 :(得分:0)

您可以尝试:

{{ dump () }}

但我不明白为什么你需要把它全部包裹在User.where(id: User.joins(:company).where(companies: {id: 0}).references(:companies)) 中?

我认为where会返回您需要的所有用户。