rewrite complicated query with union in arel?
I have the following models
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
and then i have the following query:
# 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
)
In short: i am looking for all couriers that have a coverage for the given country-code or a coverage with an empty country-code instead (the fallback).
开发者_Go百科The query works, but i am wondering if there are any better ways to write it?
If you wanted to keep the find_by_sql
you could condense the query into:
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 ]
With arel it seems not very difficult to get something similar:
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)))
This will perform one query that gets the coverages and associated couriers for the given conditions. I do not believe it would be very difficult to adapt this in order to get the intended result.
精彩评论