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

更新:コメントに応じて

さて、私は質問を誤解しました。2 つのクエリでデータベースにヒットしないように、サブクエリで選択する列名を明示的にリストする必要があると思います (これは、ActiveRecord が最も単純なケースで行うことです)。

サブセレクトで使用できprojectます:select

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 に答える