复杂查询,使用:include和:同时加入?

时间:2012-01-07 16:47:15

标签: sql ruby-on-rails

(使用Rails 3.1.3)

我有一个管理产品的应用。我从几个经销商处导入产品,他们都将其类别命名为不同。因此,我有resellercategories映射到我自己的子类别。

分类

子类别(belongs_to类别)

Resellercategories(belongs_to Subcategory)

产品(belongs_to Resellercategory)

您可以在此处查看模型以及如何定义关系: http://snipt.net/Linuus/category-and-subcategory?key=38ba590408ac4233927a06046eeca30d

在我的网站上,我想轻松地显示类别及其子类别。

如果用户仅为“女性”产品过滤产品,我还要过滤类别和子类别,以便仅显示具有“女性”产品的类别和子类别。性别存储在产品中。

那么,我该怎么做呢?

我尝试创建这样的查询: http://snipt.net/Linuus/categories-1/?key=2d5d54fd573f0afe60eaa3c47a23fd4d (我认为)过滤正确的类别。但是,当我做类似的事情时:

@menu_categories.each do |c|
    c.subcategories.each do |sc|
        # do something...
    end
end

它仍会查询所有子类别是否有女性产品。因此,我在Ruby on Rails Google Group上建议使用.includes()急切加载:subcategories。所以,像这样:

Category.includes(:subcategories)
        .joins("INNER JOIN resellercategories AS r ON subcategories.id = r.subcategory_id")
        .joins("INNER JOIN products AS p ON r.id = p.resellercategory_id")
        .group("categories.id")
        .order("categories.name ASC")
        .where("p.gender = 'unisex' OR p.gender = 'female'")
        .where("subcategories.id > 0") # Dummy to trigger eager loading

然而,当混合.includes()和.joins()时,包含似乎无法加载任何东西。因此抛出以下错误:

ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column: subcategories.id:
SELECT "categories".* FROM "categories" 
INNER JOIN resellercategories AS r ON subcategories.id = r.subcategory_id 
INNER JOIN products AS p ON r.id = p.resellercategory_id 
WHERE (p.gender = 'unisex' OR p.gender = 'female') 
GROUP BY categories.id 
ORDER BY categories.name ASC

预计会出现这种情况吗?这是一个错误吗? 我试图以正确的方式做到这一点还是有更好的方法来做到这一点?

非常感谢任何帮助。

(关于RoR Google Group的讨论:https://groups.google.com/forum/?pli=1#!topic/rubyonrails-talk/UkCF7jbehHk

解决方案: 好的,所以解决方案是使用eager_load()而不是includes()。我也不得不删除组() 这似乎对我有用:

 Category.eager_load(:subcategories)
         .joins("INNER JOIN resellercategories AS r ON subcategories.id = r.subcategory_id")
         .joins("INNER JOIN products AS p ON r.id = p.resellercategory_id")
         .order("categories.name ASC")
         .where("p.gender = 'unisex' OR p.gender = 'female'")

2 个答案:

答案 0 :(得分:1)

Rails并不总是使用连接来实现包含。您也可以通过eager_load而不是includes强制执行此操作。

答案 1 :(得分:1)

这条AR链看起来更干净。

Category.joins({:subcategories => 
               {:resellercategories =>
                :products}})
         .includes(:subcategories)
         .where('products.gender = unisex OR
                 products.gender = ?', gender)

但我不认为这会解决你获得所有subcategories的原始问题。要解决这个问题,你实际上必须查询关联。

@menu_categories.each do |c|
    c.subcategories.joins({:resellercategories =>
                           :products}})
                   .where('products.gender = unisex OR
                           products.gender = ?', gender)
                   .each do |sc|
        # do something...
    end
end