我环顾四周,找不到任何答案。所有答案都涉及不使用GROUP BY。
背景 我有一个paginator,它将为ActiveRecord.find提供选项。它添加了:limit和:offset选项并执行查询。我还需要做的是计算记录总数(减去限制),但有时查询包含:group选项,ActiveRecord.count尝试返回GROUP BY返回的所有行及其每个计数。我在Rails 2.3.5中这样做。
我想要的是ActiveRecord.count返回GROUP BY返回的行数。
以下是一些示例代码,演示了此实例(用于查找所有标记并按照标记的帖子数量排序):
options = { :select => 'tags.*, COUNT(*) AS post_count',
:joins => 'INNER JOIN posts_tags', #Join table for 'posts' and 'tags'
:group => 'tags.id',
:order => 'post_count DESC' }
@count = Tag.count(options)
options = options.merge { :offset => (page - 1) * per_page, :limit => per_page }
@items = Tag.find(options)
使用:select选项,Tag.count生成以下SQL:
SELECT count(tags.*, COUNT(*) AS post_count) AS count_tags_all_count_all_as_post_count, tags.id AS tags_id FROM `tags` INNER JOIN posts_tags GROUP BY tags.id ORDER BY COUNT(*) DESC
正如你所看到的那样,只是在'tags。*,COUNT(*)'周围包裹了一个COUNT(),并且MySQL在COUNT中抱怨了COUNT。
如果没有:select选项,它会生成此SQL:
SELECT count(*) AS count_all, tags.id AS tags_id FROM `tags` INNER JOIN posts_tags GROUP BY tags.id ORDER BY COUNT(*)
返回整个GROUP BY结果集而不是行数。
有没有办法解决这个问题,还是我必须破解分页器来解决GROUP BYs的问题(我将如何做到这一点)?
答案 0 :(得分:24)
好像你需要单独处理分组查询。在没有组的情况下进行计数会返回一个整数,而使用组计数会返回一个哈希:
Tag.count
SQL (0.2ms) SELECT COUNT(*) FROM "tags"
=> 37
Tag.count(:group=>"tags.id")
SQL (0.2ms) SELECT COUNT(*) AS count_all, tags.id AS tags_id FROM "tags"
GROUP BY tags.id
=> {1=>37}
答案 1 :(得分:16)
如果您使用的是Rails 4或5,您也可以执行以下操作。
Tag.group(:id).count
答案 2 :(得分:8)
我的情况的解决方法似乎是替换:group => 'tags.id'用:select =>执行计数之前,选项哈希中的'DISTINCT tags.id'。
count_options = options.clone
count_options.delete(:order)
if options[:group]
group_by = count_options[:group]
count_options.delete(:group)
count_options[:select] = "DISTINCT #{group_by}"
end
@item_count = @type.count(count_options)
答案 3 :(得分:3)
另一个(hacky)解决方案:
selection = Tag.where(...).group(...)
count = Tag.connection.select_value "select count(*) from (" + selection.to_sql + ") as x"
答案 4 :(得分:2)
如果我正确理解了你的问题,那么如果你根本不使用Tag.count就可以了。在select hash中指定'COUNT(*)AS post_count'就足够了。例如:
@tag = Tag.first(options)
@tag.post_count
如您所见,可以从@tag实例访问查询中的post_count值。如果你想获得所有标签,那么可能是这样的:
@tags = Tag.all(options)
@tags.each do |tag|
puts "Tag name: #{tag.name} posts: #{tag.post_count}"
end
更新
可以使用要计数的属性以及参数:distinct
来调用Countoptions = { :select => 'tags.*, COUNT(*) AS post_count',
:joins => 'INNER JOIN posts_tags', #Join table for 'posts' and 'tags'
:group => 'tags.id',
:order => 'post_count DESC',
:offset => (page - 1) * per_page,
:limit => per_page }
@count = Tag.count(:id, :distinct => true, :joins => options[:joins])
@items = Tag.find(options)