Active Record使用不同的where语句减去两个值?

时间:2016-06-27 20:54:00

标签: ruby-on-rails ruby

我一直试图绕着正确的轨道方式来做这件事。我有两张桌子,一张是与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

1 个答案:

答案 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。上面的代码未经测试,因此可能包含一两个错误。如果它不起作用请评论,我会帮忙解决。