进行连接时选择唯一的行

发布于 2024-12-05 23:55:00 字数 1867 浏览 0 评论 0原文

拳头一点背景: 我正在使用 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'])

现在你可能会说这是不可能的,因为“数据库应该如何知道从连接到每辆车的所有卖家中选择哪个:kind?”但我不在乎,因为它们都是一样的,所以它是第一个还是最后一个卖家并不重要,它从中获取属性值。 如果我执行 .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'

当然,这给了我重复项,它给出了完美的意义 - 但我该如何解决它? - 因为这不是我想要的。

我可以看到两种可能的解决方案: 首先,如果我能以某种类似 Rails 的方式让它执行,

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

它似乎会给我正确的东西。

第二如你所见,我添加了一个 :uniq =>;对协会来说是正确的,但据我所知,如果我向卖家声明并要求这样的汽车,这只会在我的示例中起作用:

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

但我对此完全不确定! 那么metawhere/metasearch 呢?我担心它也会干扰这一点。

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, :through => :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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

╭⌒浅淡时光〆 2024-12-12 23:55:00

include 执行 LEFT OUTER JOIN,这确实会创建重复项。如果您不需要在查询后访问每个@car.seller(n+1 查询问题),只需使用联接即可:

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

联接执行 INNER JOIN,因此您不应获得重复项。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文