如何解决Rails通过:created_at对表进行分组,返回:status列的计数,然后对:status列进行子分组,并包含每个唯一值的计数
我用另一种方法添加了第二个答案,我相信它会更好,因为它高效并且可以转换为数据库视图。
每当我遇到很多对数据库的重复点击或无法很好地翻译的大型,复杂查询时,我都希望使用纯sql,因为这样可以将其用作DB中的视图。我问这个问题是因为我的sql很差。我认为这可以适应您的需求,尤其是在“状态”字段是一组已知的可能值的情况下。这是我最初尝试的方式:
您可以在psql中对此进行测试。
SELECT created_at, count(status) AS total,
sum(case when status = 'error' then 1 end) AS errors,
sum(case when status = 'pending' then 1 end) AS pending,
sum(case when status = 'sent' then 1 end) AS sent
FROM notifications
GROUP BY created_at;
这应该返回一个数据透视表,如下所示:
| created_at |total|errors|pending|sent|
----------------------------------------------
| Mon, 05 Oct 2015 |2572 |500 |12 |null|
| Tue, 06 Oct 2015 |555 |null |12 |50 |
太好了,任何一张表在Rails中都是一个简单的查询,它将以对象数组的形式加载它。这些对象中的每一个将具有与每一列相对应的方法。如果该行的nil
列为null,则Rails将作为该值传递。
@stats = Notification.where(user: users).find_by_sql("SELECT created_at, count(status)
AS total,
sum(case when status = 'error' then 1 end) AS errors,
sum(case when status = 'pending' then 1 end) AS pending,
sum(case when status = 'sent' then 1 end) AS sent
FROM notifications
GROUP BY created_at;")
这将返回一个Notification
对象数组…
=> [#< Notification id: nil, created_at: "2014-02-07 22:36:30">
#< Notification id: nil, created_at: "2014-06-26 02:07:51">,
#< Notification id: nil, created_at: "2015-04-26 21:37:09">,
#< Notification id: nil, created_at: "2014-02-07 22:48:29">,
#< Notification id: nil, created_at: "2014-11-04 23:39:07">,
#< Notification id: nil, created_at: "2015-01-27 17:46:50">,...]
请注意,该Notification
id:
值为nil。这是因为这些对象并不代表数据库中的实际对象,而是代表查询所产生的表中的一行。但是现在您可以执行以下操作:
@stats.each do |daily_stats|
puts daily_stats.attributes
end
#{"created_at" => "Mon, 05 Oct 2015", "total" = 2572, "errors" => 500, "pending" => 12, "sent" => nil}
#{"created_at" => "Tue, 06 Oct 2015", "total" = 555, "errors" => nil, "pending" => 12, "sent" => 50}
等等。您的@stats
变量很容易传递到视图,在该视图中可以轻松地将其打印为.html.erb
文件中的表格。您可以访问数组中任何Notification对象的属性,如下所示:
@stats[0].created_at
#=> "Mon, 05 Oct 2015"
@stats[1].pending
#=> 12
CREATE VIEW daily_stats AS
SELECT user_id, created_at, count(status) AS total,
sum(case when status = 'error' then 1 end) AS errors,
sum(case when status = 'pending' then 1 end) AS pending,
sum(case when status = 'sent' then 1 end) AS sent
FROM notifications
GROUP BY user_id, created_at;
现在您可以得到结果
Select * FROM daily_stats;
请注意,我故意不限制用户的使用,就像您在原始问题中一样,并在SELECT中添加了user_id。我们正在直接在数据库中工作,它应该可以轻松地从该视图生成带有每个日期的所有用户统计信息的表。对于您正在做的事情,这是一个非常强大的数据集。现在,您可以在Rails中设置虚拟模型,并轻松获取所有数据,而不会扭曲Rails查询。
app / models / daily_stat.rb:
class DailyStat < ActiveRecord::Base
belongs_to :user
#this is a model for a view in the DB called dash_views
#class name is singular and will automatically look for the table "daily_stats" which his snake_case and plural.
end
将相应的关系添加到您的User
模型:
class User < ActiveRecord::Base
has_many :daily_stats
end
users = [2]
DailyStat.where(user: users)
=> AllStat Load (2.8ms) SELECT "all_stats".* FROM "all_stats" WHERE "all_stats"."category_id" = 2
=> [ #<AllStat user_id: 2, created_at: "2014-02-14 00:30:24", total: 300, errors: 23, pending: nil, sent: 3>,
#<AllStat user_id: 2, created_at: "2014-11-29 00:18:28", total: 2454, errors: 3, pending: 45, sent: 323>,
#<AllStat user_id: 2, created_at: "2014-02-07 22:46:59", total: 589, errors: 33, pending: 240, sent: 68>...]
并在另一个方向:
user = User.first
user.daily_stats
#returns array of that users DailyStat objects.
关键是“从最低层次解决问题”。解决数据库中的数据查询问题,然后使用Rails进行操作并显示它。
解决方法
我有一个通知模型,我想知道每天创建多少个通知以及每种状态有多少个。status
是通知模型的字符串键。
Notification.where(user: users).group('DATE(created_at)').count('created_at')
那给我:
{Mon,05 Oct 2015=>2572,Tue,06 Oct 2015=>555,Wed,07 Oct 2015=>2124,Thu,08 Oct 2015=>220,Fri,09 Oct 2015=>36}
但是我想要这样的东西:
{Mon,05 Oct 2015=>{total=>2572,error=>500,pending=>12},06 Oct 2015=>{total=>555,sent=>50,pending=>12}}
或类似。活动记录是否有可能?也许group_by对我有好处。但它已被弃用。
目前,我已经尝试过:
Notification.where(user: users).group('DATE(created_at),status').count('created_at')
# => {"error"=>2,"sent"=>42}
这不是我想要的结果。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。