85

使用 SQL,我可以轻松地进行这样的子查询

User.where(:id => Account.where(..).select(:user_id))

这会产生:

SELECT * FROM users WHERE id IN (SELECT user_id FROM accounts WHERE ..)

如何使用 rails 的 3 activerecord/arel/meta_where 做到这一点?

我确实需要/想要真正的子查询,没有 ruby​​ 解决方法(使用多个查询)。

4

5 回答 5

130

Rails 现在默认执行此操作 :)

Message.where(user_id: Profile.select("user_id").where(gender: 'm'))

将产生以下 SQL

SELECT "messages".* FROM "messages" WHERE "messages"."user_id" IN (SELECT user_id FROM "profiles" WHERE "profiles"."gender" = 'm')

(“现在”指的版本号很可能是3.2)

于 2012-05-31T17:39:20.703 回答
43

在 ARel 中,这些where()方法可以将数组作为参数来生成“WHERE id IN...”查询。所以你写的内容是正确的。

例如,下面的 ARel 代码:

User.where(:id => Order.where(:user_id => 5)).to_sql

...相当于:

User.where(:id => [5, 1, 2, 3]).to_sql

... 将在 PostgreSQL 数据库上输出以下 SQL:

SELECT "users".* FROM "users" WHERE "users"."id" IN (5, 1, 2, 3)" 

更新:回应评论

好吧,所以我误解了这个问题。我相信您希望子查询显式列出要选择的列名,以便不使用两个查询访问数据库(这是 ActiveRecord 在最简单的情况下所做的)。

您可以projectselect子选择中使用:

accounts = Account.arel_table
User.where(:id => accounts.project(:user_id).where(accounts[:user_id].not_eq(6)))

...这将产生以下SQL:

SELECT "users".* FROM "users" WHERE "users"."id" IN (SELECT user_id FROM "accounts" WHERE "accounts"."user_id" != 6)

我真诚地希望这次我已经给了你你想要的!

于 2011-04-18T21:06:58.627 回答
23

我自己也在寻找这个问题的答案,我想出了另一种方法。我只是想我会分享它-希望它对某人有所帮助!:)

# 1. Build you subquery with AREL.
subquery = Account.where(...).select(:id)
# 2. Use the AREL object in your query by converting it into a SQL string
query = User.where("users.account_id IN (#{subquery.to_sql})")

答对了!班戈!

适用于 Rails 3.1

于 2012-01-03T05:55:54.940 回答
0

另一种选择:

Message.where(user: User.joins(:profile).where(profile: { gender: 'm' })
于 2018-09-26T18:00:09.437 回答
0

这是使用 rails ActiveRecord 和使用 JOIN 的嵌套子查询的示例,您可以在其中为每个查询添加子句以及结果:

您可以在模型文件中添加嵌套的 inner_query 和 outer_query 范围并使用...

  inner_query = Account.inner_query(params)
  result = User.outer_query(params).joins("(#{inner_query.to_sql}) alias ON users.id=accounts.id")
   .group("alias.grouping_var, alias.grouping_var2 ...")
   .order("...")

范围示例:

   scope :inner_query , -> (ids) {
    select("...")
    .joins("left join users on users.id = accounts.id")
    .where("users.account_id IN (?)", ids)
    .group("...")
   }
于 2019-02-15T09:35:30.447 回答