[ruby-on-rails-3.1] activerecord의 하위 쿼리

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를 사용하여 어떻게 할 수 있습니까?

실제 하위 쿼리가 필요하거나 루비 해결 방법이 없습니다 (여러 쿼리 사용).



답변

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 일 가능성이 높습니다.)


답변

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가 수행하는 작업)를 사용하여 데이터베이스에 도달하지 않도록 선택할 열 이름을 하위 쿼리에 명시 적으로 나열하기를 원한다고 생각합니다.

당신은 사용할 수 있습니다 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)

이번에는 당신이 원했던 것을 진심으로 바랍니다!


답변

나는이 질문에 대한 답을 직접 찾고 있었고 대안적인 접근법을 생각해 냈습니다. 나는 그것을 공유 할 것이라고 생각했습니다. 누군가에게 도움이되기를 바랍니다! 🙂

# 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에서 작동


답변

또 다른 대안 :

Message.where(user: User.joins(:profile).where(profile: { gender: 'm' })


답변

다음은 레일 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("...")
   }


답변