class blogs
has_and_belongs_to_many :categories
end
class categories
has_and_belongs_to_many :blogs
end
SELECT COUNT(DISTINCT `blogs`.`id`) FROM `blogs` LEFT OUTER JOIN `blogs_categories` ON `blogs_categories`.`blog_id` = `blogs`.`id` WHERE `blogs`.`status` = 2 AND (`blogs_categories`.`category_id` = 3 AND `blogs_categories`.`category_id` = 2)
为什么不是where blogs_categories.category_id in (2,3) and blogs.status = 2
?
就算是要同时满足 (2,3) 的话也可以直接在关系表上查啊,没必要连接 categories 表吧……
我最近也是碰到这个问题,我的方法是:
-- 把 含有 [2,3] 分类的 blog_id 查询出来
select blog_id, count(1) c from blogs_categories where category_id in (2,3) group by blog_id having c = 2
@jiemoon 你的确查出了 2 和 3 的部分博客,但是如果 category_id 有 2 和 3 和 4 的博客就查不出来
~~我觉得应该这样
select blog_id, count(1) c from blogs_categories where category_id in (2,3) group by blog_id having c >= 2
#5 楼 @colorfulberry 直接 =
是可以的,因为 category_id in (2,3)
这个条件会把含有 2
or 3
的 category_id 的博客查询出来(也包括 category_id
有 2
和 3
和 4
的博客)
@jiemoon 目前我的采纳的做法是用了 querybuilder
q = query
category_ids.each do |category_id|
blog_category_table_alias = BlogCategory.arel_table.alias("%s_%s" % [BlogCategory.table_name, category_id])
q = q.joins(
Blog.arel_table.join(blog_category_table_alias, Arel::Nodes::InnerJoin)
.on(
Blog[:id].eq(blog_category_table_alias[:blog_id]).and(
blog_category_table_alias[:category_id].eq(category_id)
)
)
.join_sources
)
end
对应的 sql
SELECT `blogs`.* FROM `blogs` INNER JOIN `blog_categories` `blog_categories_2` ON `blogs`.`id` = `blog_categories_2`.`blog_id` AND `blog_categories_2`.`category_id` = 2 INNER JOIN `blog_categories` `blog_categories_3` ON `blogs`.`id` = `blog_categories_3`.`blog_id` AND `blog_categories_3`.`category_id` = 3 WHERE `blogs`.`status` = 2
sql 时根据 category_id 动态生成的 如下:
pry(main)> BlogQueryBuilder.new.for_xxx([2,3]).to_sql
=> "SELECT `blogs`.* FROM `blogs` INNER JOIN `blog_categories` `blog_categories_2` ON `blogs`.`id` = `blog_categories_2`.`blog_id` AND `blog_categories_2`.`category_id` = 2 INNER JOIN `blog_categories` `blog_categories_3` ON `blogs`.`id` = `blog_categories_3`.`blog_id` AND `blog_categories_3`.`category_id` = 3 WHERE `blogs`.`status` = 2"
[6] pry(main)> BlogQueryBuilder.new.for_xxx([1,2,3,4]).to_sql
=> "SELECT `blogs`.* FROM `blogs` INNER JOIN `blog_categories` `blog_categories_1` ON `blogs`.`id` = `blog_categories_1`.`blog_id` AND `blog_categories_1`.`category_id` = 1 INNER JOIN `blog_categories` `blog_categories_2` ON `blogs`.`id` = `blog_categories_2`.`blog_id` AND `blog_categories_2`.`category_id` = 2 INNER JOIN `blog_categories` `blog_categories_3` ON `blogs`.`id` = `blog_categories_3`.`blog_id` AND `blog_categories_3`.`category_id` = 3 INNER JOIN `blog_categories` `blog_categories_4` ON `blogs`.`id` = `blog_categories_4`.`blog_id` AND `blog_categories_4`.`category_id` = 4 WHERE `blogs`.`status` = 2"