涉及多态关联的复杂时间序列统计聚合

ker*_*lin 11 mysql sql ruby-on-rails aggregation polymorphic-associations

好.请耐心等待,因为我需要提供大量的背景细节才能对我的问题征求合理的答案.

我有一个网站,允许您每日选股.它的工作方式是,提示您在当天面临关闭的公司之间进行选择.例如,GE与IBM.您可以选择两种类型:性能(哪种股票表现更好?)和总成交量(合并后的股票交易量是否高于或低于X?).你每天获得100美元的虚拟美元来进行选择.

最终,我们的目标是跟踪哪个用户在以下时间段内以不同类别(下文解释)的每次选择赚取最多钱:5天,15天,30天,90天,180天,1年,全部 - 时间.计算每次选择的金额非常简单.这是总赚钱(或丢失)/选秀数量.

现在,用户选择的每个公司都属于分类层次结构.通常,分类层次结构如下所示:

分部 - >主要集团 - >产业集团 - >分类 - >公司

这里有些例子:

  • 采矿 - >金属采矿 - >铁矿石 - >棕色矿石采矿 - >公司A.
  • 采矿 - >金属采矿 - >铁矿石 - >棕色矿石采矿 - >公司B.
  • 采矿 - >金属采矿 - >铁矿石 - >褐铁矿矿业 - >公司C.
  • 采矿 - >金属采矿 - >铁矿石 - >褐铁矿采矿 - >公司D.
  • 制造业 - >烟草产品 - >雪茄 - > Stogies - >公司E.
  • 制造业 - >烟草产品 - >雪茄 - > Stogies - >公司F.
  • 制造业 - >烟草产品 - >雪茄 - >小雪茄 - >公司G.
  • 制造业 - >烟草产品 - >雪茄 - >小雪茄 - >公司H.
  • …等等…

每个类别(当然还有相应的表)都有一个模型,它们与你上面看到的相关(想想foreign_key).

Matchup有一个模型,每个记录代表当天哪些公司正面临关闭.每条记录都会跟踪每家公司的起始和最终股票价格,以及总交易量.

每个Matchup都有一个或多个:pick_prices,可以全天更改.通常,每场比赛都有一个表现选择价格和一个总体积选择价格.价格决定了你选择的费用以及正确选择的收入.(现在,这只是背景信息.您无需担心这些特定的价格计算.)

在交易日结束时,用户的选择权被解决.选择在Pick模型中表示,具有以下属性:

  • 用户身份
  • amount_spent(例如,10美元)
  • 结果(例如,WON,LOST)
  • 选择(例如,公司A)
  • matchup_id
  • pick_price_id
  • amount_won
  • 已解决(真或假)
  • created_at
  • 的updated_at

目前,当每个选择被解析时,另一个表名为pick_records,它具有以下属性:

  • 用户身份
  • recordable_id
  • recordable_type(分部或主要集团或行业集团或分类或公司)
  • 选秀权(总选秀权,不论选秀类型)
  • 赢了(总选秀权赢了,不管选秀类型)
  • 丢失(总选秀权丢失,不论选秀类型)
  • 钱(赢得的总金额)
  • money_per_pick(钱/选秀权)
  • performance_picks
  • performance_won
  • performance_lost
  • performance_money
  • performance_money_per_pick
  • volume_picks
  • volume_won
  • volume_lost
  • volume_money
  • volume_money_per_pick
  • created_at
  • 的updated_at

如您所知,这是一个多态模型.该表聚合了所有时间选择记录统计信息.

所以现在是挑战:

鉴于现有设计,我需要做些什么才能在以下时间段内捕获用户的选择记录:5天,15天,30天,90天,180天,1年,所有时间?它需要简单,高效,快速!

我目前正在MySQL DB上运行Rails 2.3.11.

Joh*_*ica 3

我不认为需要表 pick_records。
您可以对任意天数执行这样的查询:

SELECT 
   user_id
   ,sum(amount_spent) 
   ,sum(IF(result = 'WON',1,0)) as WON_count
   ,sum(IF(result = 'LOST',1,0)) as LOST_count
   ,pick 
   /*matchup_id*/
   ,sum(pc.price) as price
   ,sum(IF(result = 'WON'),amount_won,0)) as amount_won
   ,sum(IF(result = 'LOST'),amount_won,0)) as amount_lost
   ,sum(IF(result = 'WON'),amount_won,-amount_won)) as nett_amount
FROM picks
INNER JOIN pick_price pc ON (pc.id = user.pick_price_id)
WHERE created_at BETWEEN DATE_SUB(NOW(), INTERVAL 5 DAY) AND NOW()
  AND resolved = 'true'
GROUP BY user_id, pick
Run Code Online (Sandbox Code Playgroud)