3

我有一份长达数年的活动日志。我被要求计算该应用程序每个用户的每周参与度。我将参与度定义为用户在任何一周内进行一项或多项记录活动。

我如何对这些活动进行分组并按周为每个用户计数?我已经阅读了很多不同的帖子,关于ruby​​ 方法sql还是 arel 语法是否最好似乎存在争议。我的用户不超过 500 个,因此性能与其说是简洁的事情一样重要。

我已经成功地尝试了这个:

user = User.first.activity_logs.group_by { |m| m.created_at.beginning_of_week } 
       # => {Mon, 11 Mar 2013 00:00:00 EDT -04:00=>
             [#<ActivityLog id: 12345, user_id: 429, ... ]}

然后唯一的下一步是我可以毫无错误地返回任何东西:

user.map { |week| week.count } => [2, 2, 2, 2, 2, 2, 2, 2]

所以看起来我把这件事弄得太复杂了。我如何简洁地计算每周的活动数量并为每个用户执行此操作?

我只是想要一些我最终可以粘贴到电子表格(例如,下面)中的东西,以便为经理制作热图或其他图表。

| User          | Week            | Activity|
| ------------- | :-------------: | -------:|
| jho           | 2013-1          | 20      |
| bmo           | 2013-1          | 5       |
| jlo           | 2013-1          | 11      |
| gdo           | 2013-2          | 2       |
| gdo           | 2013-5          | 3       |
| jho           | 2013-6          | 5       |

编辑

作为其他人的参考:
Rails 3.1
Using PostgreSQL 9.1.4
Here is the schema file from ruby​​ on rails

create_table "activity_logs", :force => true do |t|
  t.integer  "user_id"
  t.string   "activity_type"
  t.datetime "created_at"
  t.datetime "updated_at"
end

| ------+| --------+| ----------------+| ----------------+ | ----------------+ | 
| id     | user_id  | activity_type    | created_at        | updated_at        | 
| ------+| --------+| ----------------+| ----------------+ | ----------------+ | 
| 28257  | 8        | User Signin      | 2013-02-14 1...   | 2013-02-14 1...   | 
| 25878  | 7        | Password Res...  | 2013-02-03 1...   | 2013-02-03 1...   | 
| 25879  | 7        | User Signin      | 2013-02-03 1...   | 2013-02-03 1...   | 
| 25877  | 8        | Password Res...  | 2013-02-03 1...   | 2013-02-03 1...   | 
| 19325  | 8        | Created report   | 2012-12-16 0...   | 2012-12-16 0...   | 
| 19324  | 9        | Added product    | 2012-12-16 0...   | 2012-12-16 0...   | 
| 18702  | 8        | Added event      | 2012-12-15 1...   | 2012-12-15 1...   | 
| 18701  | 1        | Birthday Email   | 2012-12-15 0...   | 2012-12-15 0...   | 
| ------+| --------+| ----------------+| ----------------+ | ----------------+ | 

解决方案

修改@Erwin Brandstetter 的命令,我在命令行上得到了想要的结果:

ActivityLogs.find_by_sql("
  SELECT user_id, to_char(created_at, 'YYYY-WW') AS week, count(*) AS activity
  FROM   activity_logs
  GROUP  BY 1, 2
  ORDER  BY 1, 2;")
4

2 回答 2

2

我从@ideamotor借了测试表并简化了它。活动类型无关紧要,将每个活动计算为1

CREATE TEMP TABLE log(usr text, day date);
INSERT INTO log VALUES 
  ('bob' , '2012-01-01')
 ,('bob' , '2012-01-02')
 ,('bob' , '2012-01-14')
 ,('susi', '2012-01-01')
 ,('susi', '2012-01-14');

查询(不会比这更简洁):

SELECT usr, to_char(day, 'YYYY-WW') AS week, count(*) AS activity
FROM   log
GROUP  BY 1, 2
ORDER  BY 1, 2;

结果:

usr  | week     | activity
-----+----------+---------
bob  | 2012-01  | 2
bob  | 2012-02  | 1
susi | 2012-01  | 1
susi | 2012-02  | 1

to_char()使这非常简单。我在这里引用手册

WW 一年中的周数 (1-53)(第一周从一年的第一天开始。)

作为替代考虑:

IWISO 一年中的周数(01 - 53;新年的第一个星期四在第 1 周。)

于 2013-03-22T01:23:26.790 回答
1

这是在 Postgresql 中。这里的诀窍是你需要生成你的 year-weekofyear 值。在这里,我从日期中提取信息并将其连接起来。

在这里,我确保“2012-01-01”不被算作第 52 周。我正在超越标准。您可能需要根据您定义周数的方式更改此功能。

create temp table daily_log(person character varying, activity numeric, 
    dayof date);
insert into daily_log values 
     ('bob'    ,1,'2012-01-01')
    ,('bob'    ,1,'2012-01-02')
    ,('bob'    ,0,'2012-01-14')
    ,('charlie',1,'2012-01-01')
    ,('charlie',1,'2012-01-14')

select person 
 ,extract('year' from dayof) || '-' || 
    case when extract('week' FROM dayof) >= 52 
         and extract('month' FROM dayof) = 1 
    then 1 
 else extract('week' FROM dayof) end as weekof
,sum(activity) as activity_cnt
from daily_log
group by weekof, person
order by person, weekof;

这会让你:

| person        | weekof          | activity_cnt|
| -------------:| :--------------:| -----------:|
| bob           | 2012-1          | 2           |
| bob           | 2012-2          | 0           |
| charlie       | 2012-1          | 1           |
| charlie       | 2012-2          | 1           |

为什么我用2012,我不知道。

这是 postgresl 手册中关于提取一周的内容(http://www.postgresql.org/docs/9.2/static/functions-datetime.html):

“这一天所在的一年中的周数。根据定义 (ISO 8601),一年的第一周包含该年的 1 月 4 日。(ISO-8601 周从星期一开始。)换句话说,一年中的第一个星期四在该年的第 1 周。(仅适用于时间戳值)

因此,1 月初的日期可能是上一年第 52 周或第 53 周的一部分。例如,2005-01-01 是 2004 年第 53 周的一部分,2006-01-01 是 2005 年第 52 周的一部分。”

于 2013-03-22T00:53:59.903 回答