新手问题 [已解决] 求教统计实现方法

chairy11 · 2014年10月14日 · 最后由 chairy11 回复于 2014年10月14日 · 2642 次阅读

问题

一时还不知道应该怎么去 google 这个问题,先发帖来问问思路哈~

目标结果是一个统计工作量的表,多个用户对应多个项目的工作量,如下图:

在 model 里面,我是用一个 workload 表的,有 user_id, project_id。 user has_many workloads, project has_many workloads. 现在这个统计表的话,它是要确定对应着每个项目每个人的工作量。那就是双维度的确定,既要是这个 project,又要正好是这个 user。 一般大家是怎么做的?难道要先来个二维数组?workload[project][user] 什么的?

解决方案

controller 中

def fetch_workloads_data(pws)
  workloads_table = Hash.new(0)
  pws.each do |pw|
    pw.workloads.each do |wl|
      workloads_table[[wl.project_id, pw.user_id]] += wl.day_count
    end
  end
  return workloads_table
end

view 中



<% @projects.each do |project|  %>
 <tr>
   <td><%= "#{project.name}-#{project.id}" %></td>
   <% @users.each do |user| %>
     <td><%= @workloads_table[[project.id, user.id]] %></td>
   <% end %>
 </tr>
 <% end %>

暂时的解决方案是:

  1. 做了一个 hash 表,本来想做个二维 hash 的,不知道为什么总报错,只好最后用一个 array 来做键,这个 array 为 [project_id, user_id]
  2. hash 默认 value 值为 0
  3. 在 view 中用 hash 提取出结果放进 td。
class User < ActiveRecord::Base
  has_many :workloads
end

class Project < ActiveRecord::Base
  has_many :workloads
end

class Workload < ActiveRecord::Base
  belongs_to :user
  belongs_to :project

  // 工作量放这个表里面
end

另外 google 的方法:http://lmgtfy.com/?q=how+to+set+many+to+many+rails

#1 楼 @MrPasserby 我的 model 结构和你是一样的。但我现在不知道怎么写的是这个统计的方法。 以前我们做列表,都是在一行中把相应的 attributes 一一列出来,比如说 user 表,有 name, tel, address,直接就是 user.name, user.tel, user.address,列就出来了。 可是我现在想要 1 个 attribute,但它是由两个参数确定的,一是 user, 另一个是 project,要恰好对应对这个表格中,如果没有,就显示为 0.

啊……好像我表达不清……

反正就是,想要的结果是那个图,多个项目多个用户对应的工作量的统计……

额,这不是数据库多对多的关系么? 把这个 attribute 加到 workloads 这个表里,在 Workload 这个 model 里加统计方法就好了。

#3 楼 @kungs 呜呜呜,还是不懂……我这还有其它嵌套的,所以没有给 workload 建 controller。我会在别的 controller 里提取。问题是,controller 的方法怎么写,view 怎么写?

我感绝大概最直观的做法会是这个样子地:

Project.all.each do |p|
  users = p. workloads.select("user_id, count(user_id)").group("user_id")
end

不知道是不是楼主说的在 controller 中的取法

#5 楼 @dn365 Yes,你对我的问题的理解方向对了。 但是这样的,再细化一点,是统计每周的每个人在每个项目上的工作量分布。 workload 表里面有 day_count 字段,这个才是工作量,然后有 user_id,project_id。

但我对你的解决方案还不太理解,我想想,你这个 count(user_id)是指这个用户出现的次数累加吗? 我再想想……

这是简单的多维报表,或交叉报表。如果出很多这样的报表,就不 y 考要虑写代码了,找一个报表工具/多维分析引擎。

#7 楼 @wushexu 暂时还不是很多。能能代码写吗?报表工具、多维分析引擎是什么?那个 wice_grid 算吗?

#6 楼 @chairy11 哦,之前不知道 workload 表设计有 day_count 字段,误理解为统计 user_id 数了 按楼主的需求再该一下估计能实现

Project.all.each do |p|
  #weeks array 按周划分时间段
  weeks = [["begin_time","end_time"]]
  weeks.each do |week|
    users = p. workloads.select("user_id, sum(day_count)").where(["created_at >= ? created_at < ?"]+ week).group("user_id")
  end
end

比较丑陋,只是实现楼主所需功能

#8 楼 @chairy11 我在 https://www.ruby-toolbox.com/categories/reporting.html 下浏览了下,遗憾的好像没有合适的报表工具。多维分析引擎即 OLAP 引擎,Ruby 更没有了。 实现一个基本的通用多维报表组件也并不难。

workload 这个表好像就是你要的统计数据吧

实现通用(多维)报表组件的要点是,要把 model、model 关联忘掉。

假设数据有 A B C D V 列,A B C D 是维度(Dimension),V 是数值列(Measure) 报表的行上显示 A B(A 列有合并单元格),列上显示 C 记 dimensions=[A,B,C,D,V],layout=[[A,B],[C]]

查出数据:sleect A,B,C,sum(V) from T group by A,B,C,按维度列分组,对数值列做聚集运算(如 sum)

转换成内存表示:{ [a1,b1]=>{c1=>v11,c2=>v22}, [a1,b2]=>{c1=>v21,c2=>v22}, [a2,b1]=>{c1=>v31,c2=>v32}, } 这是根据 dimensions 和 layout 自动生成的,是一般化的。这只是其中一种表示。

生成表格:A,B 取值有多少组合就要多少行,C 有多少取值就有多少列 如果行或列上有多个维度,生成表格时要处理合并单元格,设置 TD/TH 的 rowspan 或 colspan 的值

#12 楼 @wushexu 呜呜呜,好深奥……有 github 上哪个项目有类似的代码吗?给我参考一下下……

#9 楼 @dn365 好的,谢谢,我先试试……

#1 楼 @MrPasserby #3 楼 @kungs #5 楼 @dn365 #12 楼 @wushexu #11 楼 @liujianhei 暂时用 hash 解决了,以后再慢慢留意更优化的方案吧。 谢谢各位哈~

需要 登录 后方可回复, 如果你还没有账号请 注册新账号