ruby-on-rails-3.1 subquery arel

ruby on rails 3.1 - Subconsultas en activerecord



ruby-on-rails-3.1 subquery (3)

Con SQL puedo hacer fácilmente sub-consultas como esta

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

Esto produce:

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

¿Cómo puedo hacer esto usando los carriles ''3 activerecord / arel / meta_where?

Necesito / quiero subconsultas reales, sin soluciones de ruby ​​(usando varias consultas).


En ARel, los métodos where() pueden tomar arrays como argumentos que generarán una consulta "WHERE id IN ...". Entonces, lo que has escrito está en la línea correcta.

Por ejemplo, el siguiente código de ARel:

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

... que es equivalente a:

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

... generaría el siguiente SQL en una base de datos PostgreSQL:

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

Actualización: en respuesta a los comentarios

De acuerdo, entonces malentendí la pregunta. Creo que desea que la subconsulta indique explícitamente los nombres de las columnas que deben seleccionarse para no golpear la base de datos con dos consultas (que es lo que ActiveRecord hace en el caso más simple).

Puede usar project para la select en su selección secundaria:

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

... que produciría el siguiente SQL:

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

¡Sinceramente espero haberle dado lo que quería esta vez!


Estaba buscando la respuesta a esta pregunta yo mismo, y se me ocurrió un enfoque alternativo. Solo pensé en compartirlo, ¡espero que ayude a alguien! :)

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

¡Bingo! Bango!

Funciona con Rails 3.1


Rails ahora lo hace por defecto :)

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

producirá el siguiente SQL

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

(El número de versión que "ahora" se refiere a lo más probable es 3.2)