2010-08-19 3 views
4

I가 다음과 같은 모델복잡한 쿼리를 arel의 유니온으로 다시 작성 하시겠습니까?

class Courier < ActiveRecord::Base 
    has_many :coverages 
end 

class Coverage < ActiveRecord::Base 
    belongs_to :courier 
    belongs_to :country_code 
end 

class CountryCode < ActiveRecord::Base  
end 

하고 난 다음 쿼리가 : 한마디로

# could i translate this into cleaner arel? 
result = Courier.find_by_sql(<<SQL 
      select * from 
      (
      select cc.*, cv.rate from couriers cc, coverages cv 
      where cv.country_code_id=#{country.id} and cv.courier_id=cc.id 
      union 
      select cc.*, cv.rate from couriers cc, coverages cv 
      where cv.country_code_id is null 
       and cv.courier_id=cc.id 
       and cv.courier_id not in (select courier_id from coverages where country_code_id=#{country.id}) 
     ) as foo order by rate asc 
SQL 
) 

을 : 나는 주어진 국가 코드 나에 대한 범위를 모두 특사를 찾고 있어요 대신 공백 국가 코드로 대체 (대체).

쿼리가 작동하지만 더 좋은 방법이 있다면 궁금합니다. 당신이이 find_by_sql 당신이에 쿼리를 응축 수 유지하고 싶었다면

+0

비슷한 질문이 있습니다. http://stackoverflow.com/questions/4522746/how-would-i-join-to-a-subselect-a-scope-using-rails-3-and-arel –

답변

1

는 : arel와

result = Courier.find_by_sql [ 
    "SELECT cc.*, cv.rate 
    FROM couriers cc inner join coverages cv on cv.courier_id = cc.id 
    WHERE cv.country_code_id = ? 
    OR (cv.country_code_id is null AND cv.courier_id NOT IN (SELECT courier_id FROM coverages WHERE country_code_id= ?)) 
    ORDER BY cv.rate asc", country.id, country.id ] 
+0

감사합니다. 너는 그래도 내 질문은 네가하는 일을하지 않는다. 노동 조합은 이유가 있습니다. 원하는 국가 코드가있는 택배가없는 경우에만 국가 코드가 nil 인 택배를 찾고 싶습니다. – nathanvda

+0

아, 그래 택배는 Coverage를 통해 여러 국가 코드를 태그로 지정할 수 있습니까? 어느 쪽이든, 나는 당신이 노동 조합이 전혀 필요 없다고 생각합니다. 당신은 단지 OR을 사용하여 하위 쿼리를 하나의 SELECT로 가져올 수 있습니다. 나는 find_by_sql로 나의 대답을 업데이트하고 arel을 독립적으로 생각하려고 노력할 것이다. – jstim

1

이 비슷한 얻을 매우 어려운 일이 아니다 것 : 이것은 하나 개의 쿼리를 수행합니다

country_code = ... 
c=Courier.arel_table 
cv=Coverage.arel_table  
courier_ids_with_country_code= Coverage.select(:courier_id).where(:country_code=>country_code) 
coverage_ids_and_condition= Coverage.select(:id) 
            .where(cv[:country_code] 
               .eq(nil) 
               .and(cv[:courier_id] 
                  .in(courier_ids_with_country_code))) 
coverage_ids_with_country_code= Coverage.select(:id) 
             .where(:country_code=>country_code) 

coverage_union_joined_with_couriers = Coverage.include(:courier) 
               .where(cv[:id] 
                .in(coverage_ids_with_country_code 
                 .union(coverage_ids_and_condition))) 

그 주어진 조건에 대한 보상 및 관련 택배를 얻습니다. 의도 한 결과를 얻으려면이를 적용하는 것이 매우 어려울 것이라고 저는 믿지 않습니다.