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

jac*_*n09 5 ruby sql postgresql activerecord ruby-on-rails

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

  • 车库has_many汽车和车库has_many预约,through: :cars
  • 汽车has_many预约
  • 预约有以下字段:
    • picked_up_at(日期时间)
    • returned_at(datetime)

此外,车库有一个场地capacity (integer),这是适合车库的最大车辆数量.

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

例如,汽车是In从一个约会的回归到下一个约会的提货,Out从约会的提货到returned_at时间.

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

我使用的是Rails 4.1和Ruby 2.0.

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

Erw*_*ter 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;
Run Code Online (Sandbox Code Playgroud)

SQL 小提琴。

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

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

然后加入时间戳位于预订内的约会。
我假设每个约会都包含较低的时间戳和排除较高的时间戳,因为这是普遍的惯例。

在我们加入车库之前进行汇总和计数(这样更快)。比较:

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

请注意,这并不完全是每个 4 小时周期的平均百分比,而只是每个时间点的当前百分比,这是真实平均值的近似值。您可能会从一个奇怪的时间戳开始,例如“2015-06-01 01:17”,这样就不会陷入可能会在整个时间或其他时间周转的预订之间,这可能会增加近似值的平均误差。

您也可以对 4 小时周期进行精确计算,但这更加复杂。一种简单的技术是将时间间隔缩短至 10 分钟或足够详细以捕获全貌的粒度。

相关(带有精确计算的示例):