报告一组记录的分组平均值

时间:2015-12-16 20:24:19

标签: sql ruby-on-rails ruby postgresql activerecord

我的目标是生成一份报告,显示一周中某一天和/或一天中某个车库的平均占用率(y轴)。我的数据模型如下:

  • 车库has_many汽车和车库has_many约会,through: :cars
  • 汽车has_many约会
  • 约会有以下字段:
    • picked_up_at(datetime)
    • returned_at(datetime)

此外,车库有一个capacity (integer)字段,这是适合车库的最大车数。

如果我有一个跨越过去6个月的约会列表,我想生成一个线图,其中x轴显示每周的每一天,分为4小时的间隔,并且y-轴显示给定日/小时间隔内6个月期间的平均占用率(车库/容量中的车辆数),我该如何收集这些数据进行报告?

E.g。从一次约会返回到下一次约会的取件时,汽车是In,并且{@ 1}}从约会的取件开始直到Out { {1}}时间。

我在从这些数据点建立连接到有意义地报告并将其呈现给最终用户的最佳方式时遇到了很多麻烦。

我正在使用Rails 4.1和Ruby 2.0。

编辑:SQL小提琴 - http://sqlfiddle.com/#!9/a72fe/1

1 个答案:

答案 0 :(得分:4)

此查询将完成所有操作(适合您添加的小提琴):

SELECT a.ts, g.*, round((a.ct * numeric '100') / g.capacity, 2) AS pct
FROM  (
   SELECT ts, c.garage_id, count(*) AS ct
   FROM   generate_series(timestamp '2015-06-01 00:00'  -- lower and
                        , timestamp '2015-12-01 00:00'  -- upper bound of range
                        , interval  '4h') ts
   JOIN   appointment a ON a.picked_up_at <= ts     -- incl. lower
                       AND (a.returned_at >  ts OR
                            a.returned_at IS NULL)  -- excl. upper bound
   JOIN   car c ON c.id = a.car_id
   GROUP  BY 1, 2
   ) a
JOIN   garage g ON g.id = a.garage_id
ORDER  BY 1, 2;

SQL Fiddle.

如果returned_at IS NULL,此查询会假定汽车仍在使用中。因此,对于其他情况不应该出现NULL,否则计算中会出错。

首先,我使用方便的generate_series()函数构建时间序列。

然后加入约会,时间戳在预订范围内 我假设每个约会都包括较低的和排除的上限时间戳,因为它是普遍的惯例。

在我们加入车库之前进行聚合和计数(以这种方式更快)。比较:

外部SELECT的百分比计算 我将bigint数字与numeric(或可选地realfloat)相乘以保留小数位数,这将在整数除法中被截断。然后我舍入到两个小数位。

注意这并不是每个4小时时段的平均百分比,而只是每个时间点的当前百分比,这是真实平均值的近似值。你可以从一个奇怪的时间戳开始,例如&#39; 2015-06-01 01:17&#39;所以不要介于可能会在整个小时或其他时间翻身的预订之间,这可能会增加近似值的平均误差。

您也可以对4小时进行精确计算,但这种方法更为复杂。一种简单的技术是将间隔缩短到10分钟或一些足够详细的粒度来捕捉全貌。

相关(使用精确计算的示例):