我一直试图绕着正确的轨道方式来做这件事。我有两张桌子,一张是与dailystats桌子有一对多关系的玩家。每天都会记录新的统计数据。我试图仅在那个月获得最高统计数据,但整体记录统计数据。所以今天的统计数据是所有月份的总数。所以我需要花费当前月份并从上个月的最后一天减去它。
我使用以下内容获取当天的最高统计数据。
@gamesplayed = Player.joins(:dailystats).select('players.*, dailystats.gamesplayed AS average_score').order('average_score desc').group('players.id').where('MONTH(statdate) = MONTH(NOW())').first.name
那么从本月的差异 - 上个月我怎么能为顶级球员做呢?我认为它看起来像这样,
@gamesplayed = (Player.joins(:dailystats).select('players.*, dailystats.gamesplayed AS average_score').where('(MONTH(statdate) = MONTH(NOW()))') - Player.joins(:dailystats).select('players.*, dailystats.gamesplayed AS average_score').where('(MONTH(statdate) = MONTH(NOW() - INTERVAL 1 MONTH)')).first.name
答案 0 :(得分:2)
您可以运行两个查询,就像您建议的解决方案一样,但-
运算符绝对不够聪明,无法处理计算每个查询的行方差异。您必须编写自己的代码来遍历每个“本月”行,找到相应的“上个月”行,并存储差异。
但您也可以在一个查询中执行此操作。在Rails的查询语法中这样做会很复杂,因为我们在这里进入了相对高级的SQL,但我会尽我所能。
Player
.joins("JOIN (SELECT player_id,
SUM(gamesplayed) as gamesplayed, COUNT(*) as count
FROM dailystats
WHERE DATE_TRUNC('MONTH', statdate) = DATE_TRUNC('MONTH', NOW())
GROUP BY player_id) this_month
ON this_month.player_id = players.id
")
.joins("JOIN (SELECT player_id,
SUM(gamesplayed) as gamesplayed, COUNT(*) as count
FROM dailystats
WHERE DATE_TRUNC('MONTH', statdate) =
DATE_TRUNC('MONTH', NOW() - INTERVAL '1 month')
GROUP BY player_id) last_month
ON last_month.player_id = players.id
")
.select('players.*')
.select('this_month.gamesplayed - last_month.gamesplayed AS gamesplayed_change')
(您可能会注意到我将MONTH()
用法更改为DATE_TRUNC('month')
;原因是MONTH将返回1,2,3,4等,这意味着如果您的网站运行时间更长去年,你会开始回到去年的数据,这是不恰当的。)
上述方法的工作方式是两次加入dailystats表;一次是本月的统计数据,一次是上个月的统计数据。但是,由于每个玩家有多个dailystats条目,我们首先通过子查询对每个月的统计数据进行分组,这样我们就可以期望每个玩家只有一行这样的行。然后,我们的SELECT子句可以使用我们上面计算的月度统计数据来获得合理的差异。
现在,上面的代码太长了,无法直接进入您的代码库。要清理它,您可能需要创建monthlystats汇总表(可以在数据库中实现为视图),或者将您的代码转换为使用原始SQL(提取到单独的模块)。
P.S。上面的代码未经测试,因此可能包含一两个错误。如果它不起作用请评论,我会帮忙解决。