Selecting unique rows when doing a join
Fist a little background: I'm using Rails 3.0.7, Postgres 9.0 and MetaWhere/MetaSearch 1.0.4
I have a very frustrating problem with getting the unique records when querying the my database. I have 3 models as follows:
class Car < ActiveRecord::Base
has_many :sellers, :through => :adverts, :uniq => true
has_many :adverts, :dependent => :destroy
end
class Seller < ActiveRecord::Base
has_many :cars, :开发者_如何学Gothrough => :adverts, :uniq => true
has_many :adverts
end
class Advert < ActiveRecord::Base
belongs_to :car, :autosave => false
belongs_to :seller, :autosave => false
end
So far so good. Now what I want to do is, to find all cars, that is Fiat Panda´s (:brand, :model_name attributes on car). This is going just fine. But if I want some information from sellers table joined in as well, the problems start to show - I'm getting duplicate cars!!! What I do is the following:
Car.includes(:adverts, :sellers).where(:brand >> 'Fiat', :model_name >> 'Panda', :sellers => [:kind >> 'Dealer'])
Now you could argue, that this is not possible, because "how should the db know which :kind to chose from all the sellers connected to each car?" But I don't care, because they are all the same, so it doesn't matter if it's the first or if it's the last seller it's taking the attributes value from. If I do a .debug_sql, I get the following:
SELECT cars.*, sellers.*, adverts.* FROM cars LEFT OUTER JOIN adverts ON adverts.car_id = cars.id LEFT OUTER JOIN adverts sellers_cars_join ON cars.id = sellers_cars_join.car_id LEFT OUTER JOIN sellers ON sellers.id = sellers_cars_join.seller_id WHERE cars.brand = 'Fiat' AND cars.model_name = 'Panda' AND sellers.kind = 'Dealer'
Of cause this gives me duplicates, it gives perfect sense - but how can I solve it? - cause it's not what I want.
I can see two possible solutions to this: First If I could somehow in a rails-like way get it to execute
SELECT DISTINCT(cars.id), cars.*, sellers.*, adverts.* FROM cars LEFT....
It seems that it would give me the right thing.
Second As you can see, I have added a :uniq => true to the associations, but this would, as far as I can see only work in my example, if I stated from sellers and asked for cars like this:
Seller.includes(:adverts, :cars).where(:cars => [:brand >> 'Fiat'], :cars => [:model_name >> 'Panda'], :kind >> 'Dealer')
But I'm not sure about this at all! And what about metawhere/metasearch - I'm fearing that it's interfering in this as well.
includes performs a LEFT OUTER JOIN, which indeed creates duplicates. If you don't need to access to each @car.seller after your query (n+1 query issue), just use joins instead :
Car.joins(:sellers).
where(:cars => {:brand => 'Fiat',
:model_name => 'Panda'},
:sellers => {:kind => 'Dealer'})
joins performs an INNER JOIN, so you shouldn't get duplicates.
精彩评论