我的问题是两个折叠。首先,我有一个未规范化的表,其中包含3对数据(6列),这些数据必须求和。它大致是这样的:
|-module_a-|-value_a-|-module_b-|-value_b-|-module_c-|-value_c-|
----------------------------------------------------------------
| 02 | 15 | nil | nil | nil | nil |
| 01 | 10 | 00 | 10 | nil | nil |
| 00 | 25 | nil | nil | nil | nil |
| 02 | 22 | 01 | 15 | 03 | 20 |
| 03 | 10 | nil | nil | nil | nil |
| 02 | 8 | 00 | 5 | nil | nil |
我的主要目标是获得每个模块的总和,但由于它们可以混合在3个字段中,因此通过activerecord(或者我认为)这样做变得复杂。
无论如何,为了清理它,我做了一个像这样的数组:
tok1=Office.select('module_a as module, value_a as value')
tok2=Office.select('module_b as module, value_b as value').where.not(:value_b => nil)
tok3=Office.select('module_c as module, value_c as value').where.not(:value_c => nil)
tok=(tok1+tok2+tok3)
结果:
|-module-|-value-|
------------------
| 02 | 15 |
| 01 | 10 |
| 00 | 25 |
| 02 | 22 |
| 03 | 10 |
| 02 | 8 |
| 00 | 10 |
| 01 | 15 |
| 03 | 20 |
| 00 | 5 |
到目前为止,非常好。
现在,我想对模块值进行总结。如果我可以通过ActiveRecord执行GROUP和SUM,这将非常简单,但结果变量tok
是一个数组,因此不可能有ActiveRecord函数。如果我尝试通过tok=tok1.merge(tok2)
合并它们,我最终只得到了tok2的结果,我认为这是因为我在查询Office表时重命名字段,我不确定。我尝试以不同的方式将它们组合在一起,但我得到的错误是关系不是不可变的。
无论如何,由于做tok=tok1+tok2+tok3
的结果以数组结束,我想把它作为一个数组来处理。我尝试过使用map
,在做了tok.map{|h| [h.module, h.value]}
之后我最终得到了这样一个数组:
{[02, 15], [01, 10], [00, 25}, [02, 22], [03,10], [02, 8], [00,10], [01,15], [03,20], [00, 5]}
我不知道如何从这里开始。我试着把它变成一个哈希,但是我对map方法还是太新了所以我不知道怎么做。理想情况下,我认为,它应该是这样的:
{ ["02" => 15],["01" => 10],["00" => 25],["02" => 22],["03" => 10],["02" => 8],
["00" => 10],["01" => 15],["03" => 20],["00" => 5]}
我已经在其他问题中读过如何用这样的散列/数组来对这些值求和,所以如果我这样得到它,我想我会被设置。
对于凌乱的解释感到抱歉。
答案 0 :(得分:3)
你可以这样做:
arr = [[02, 15], [01, 10], [00, 25], [02, 22], [03,10], [02, 8], [00,10], [01,15], [03,20], [00, 5]]
hash = {}
arr.each do |item|
hash[item[0]] ||= 0
hash[item[0]] += item[1]
end
hash # => {2=>45, 1=>25, 0=>40, 3=>30}
或没有上一张地图:
hash = {}
tok.each do |item|
hash[item.module] ||= 0
hash[item.module] += item.value
end
编辑:正如Dima Goltsman的评论中提到的那样(谢谢!)它可以使用注入以更短的形式重写:
arr = [[02, 15], [01, 10], [00, 25], [02, 22], [03,10], [02, 8], [00,10], [01,15], [03,20], [00, 5]]
arr.inject(Hash.new(0)) do |hash, item|
hash[item[0]] += item[1]
hash
end # => {2=>45, 1=>25, 0=>40, 3=>30}
或
tok.inject(Hash.new(0)) do |hash, item|
hash[item.module] += item.value
hash
end
答案 1 :(得分:1)
数据库通常非常擅长分组和添加内容,因此我可能会在SQL中尽可能多地执行此操作。
tok = Office.find_by_sql <<-END_SQL
SELECT module, SUM(value)
FROM (
SELECT module_a AS module, value_a AS value FROM offices
UNION
SELECT module_b AS module, value_b AS value FROM offices WHERE value_b IS NOT NULL
UNION
SELECT module_c AS module, value_c AS value FROM offices WHERE value_c IS NOT NULL
) AS modules(module, value)
GROUP BY module
END_SQL
使用以下属性评估Office
个实例的集合:
+--------+-------+
| module | value |
+--------+-------+
| 1 | 25 |
| 3 | 30 |
| 0 | 40 |
| 2 | 45 |
+--------+-------+
如果由我决定,我可能会使用给定的SQL查询创建一个视图,并在其上添加一个ActiveRecord数据模型。这样,Office
模型不会用于除最初预期之外的目的。由于实现视图在DBMS和分支之间因原始主题而异,因此我不会在此详细介绍。