count方法根据条件

时间:2017-11-23 10:26:08

标签: mysql ruby-on-rails activerecord

我正在运行一个查询,该查询查看数据库中过去三天(今天包括)中记录活动的天数,使用GroupBy gem按天分组。以下是完整查询:

Record.activities.where("created_at >= ?", 2.days.ago.beginning_of_day.in_time_zone).group_by_day(:created_at).count.count

2天前,我有1个活动,昨天我有0个,今天我有2个。这应该返回2个(不是3个,它计算的日子不是活动)但是由于某种原因它会返回3.更奇怪的是如果我将2.days.ago更改为1.day.ago0.days.ago,则会返回正确的值,1。它会忽略昨天没有活动的地方,只计算它在那里识别的那一天(今天)是一项活动。

如果我删除了第二个.count,则返回2.days.ago的内容...

{Tue, 21 Nov 2017=>1, Wed, 22 Nov 2017=>0, Thu, 23 Nov 2017=>2} 

如果我为1.day.ago运行它,我会......

{Thu, 23 Nov 2017=>2} 

以下是2.days.ago查询的原始SQL ..

SELECT COUNT(*) AS count_all, strftime('%Y-%m-%d 00:00:00 UTC', created_at) 
AS strftime_y_m_d_00_00_00_utc_created_at 
FROM "activities" 
WHERE "activities"."goal_id" = ? AND (created_at >= '2017-11-21 00:00:00') 
AND (created_at IS NOT NULL) 
GROUP BY strftime('%Y-%m-%d 00:00:00 UTC', created_at)

经过一些更多的测试,我发现如果x.days.ago中的x落在0的那一天,它只会忽略一天有0个活动。如果有0个活动超过1天,它将忽略第一个一个应该的,但然后计算其他几天0后来......

不确定我在这里缺少什么,但感谢任何帮助找到问题。

如果您需要更多信息,请与我们联系。

3 个答案:

答案 0 :(得分:2)

您可以使用.having('count(activities.id) > 0')忽略没有活动的天数

下面未经测试的查询:

Record.activities
  .select('count(activities.id) as count_all,date(activities.created_at) as day')
  .where("created_at >= ?", 2.days.ago.beginning_of_day.in_time_zone)
  .group('day').having('count_all > 0')

答案 1 :(得分:0)

我找到了一种方法来返回正确的结果,但仍然很想知道为什么初始查询会返回这些结果。

以下是有效的查询:

Record.activities.where("created_at >= ?", 4.days.ago.beginning_of_day.in_time_zone).group_by_day(:created_at).count.reject {|k,v| v == 0 }.count

答案 2 :(得分:0)

首先你的解决方案是不行的,因为你需要在sql查询中进行它(当你将所有数据加载到ruby对象然后对它们进行排序。它将在规模期间成为瓶颈)。把同样的东西放到sql上。我认为这个应该有效:

Record.activities.where("created_at >= ? AND count_all > 0", 2.days.ago.beginning_of_day.in_time_zone).group_by_day(:created_at).count

然后了解为什么在期望得到3时得到3的原因.Sql COUNT(*)返回行数。在您的情况下,您将始终有3个独特的日期,因此3个唯一的行(group_by按其唯一性对它们进行分组)。您必须按我在查询中的0次计算过滤天数,以过滤行数,但计数为0,但仍会计算