Выбор уникальных строк при выполнении объединения - PullRequest
3 голосов
/ 22 сентября 2011

Немного предыстории: я использую Rails 3.0.7, Postgres 9.0 и MetaWhere / MetaSearch 1.0.4

У меня очень неприятная проблема с получением уникальных записей при запросах к моей базе данных.У меня есть 3 модели следующим образом:

class Car < ActiveRecord::Base
  has_many    :sellers, :through => :adverts, :uniq => true
  has_many    :adverts, :dependent => :destroy
end

class Seller < ActiveRecord::Base
  has_many :cars, :through => :adverts, :uniq => true
  has_many :adverts
end

class Advert < ActiveRecord::Base
  belongs_to :car, :autosave => false
  belongs_to :seller, :autosave => false
end

Пока все хорошо.Теперь я хочу найти все машины Fiat Panda (атрибуты: brand,: model_name на автомобиле).Это идет просто отлично.Но если я хочу получить некоторую информацию из таблицы продавцов, проблемы начинают проявляться - я получаю дубликаты автомобилей !!!Я делаю следующее:

Car.includes(:adverts, :sellers).where(:brand >> 'Fiat', :model_name >> 'Panda', :sellers => [:kind >> 'Dealer'])

Теперь вы можете утверждать, что это невозможно, потому что "как БД узнает, какой: любезно выбрать из всех продавцов, подключенных к каждой машине?"Но мне все равно, потому что они все одинаковые, поэтому не имеет значения, является ли он первым или последним продавцом, с которого он берет значение атрибутов.Если я делаю .debug_sql, я получаю следующее:

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'

Потому что это дает мне дубликаты, это дает прекрасный смысл - но как я могу решить это?- потому что это не то, что я хочу.

Я вижу два возможных решения этого: во-первых, если бы я мог каким-то образом, как рельсы заставить его выполнить

SELECT DISTINCT(cars.id), cars.*, sellers.*, adverts.* FROM cars LEFT....

Кажется, чтоэто дало бы мне правильную вещь.

Секунда Как вы можете видеть, я добавил: uniq => true к ассоциациям, но, насколько я могу видеть, в моем примере это работает только в том случае, еслиЯ заявил от продавцов и попросил автомобили, как это:

Seller.includes(:adverts, :cars).where(:cars => [:brand >> 'Fiat'], :cars => [:model_name >> 'Panda'], :kind >> 'Dealer')

Но я совсем не уверен в этом!А как насчет metawhere / metasearch - я боюсь, что это тоже мешает.

1 Ответ

5 голосов
/ 22 сентября 2011

включает выполнение LEFT OUTER JOIN, которое действительно создает дубликаты. Если вам не нужен доступ к каждому @ car.seller после запроса (проблема n + 1), просто используйте вместо этого объединения:

Car.joins(:sellers).
    where(:cars => {:brand => 'Fiat', 
                    :model_name => 'Panda'}, 
          :sellers => {:kind => 'Dealer'})

объединения выполняет ВНУТРЕННЕЕ СОЕДИНЕНИЕ, поэтому вы не должны получать дубликаты.

...