class User < ApplicationRecord
has_many :visits
end
class Visit < ApplicationRecord
belongs_to :user
belongs_to :building
end
class Building < ApplicationRecord
has_many :visits
end
我有上述关系。访问具有start_at
和end_at
,它们是时间戳。我试图找出用户在建筑物上花费的平均时间。我有以下查询。
visits.select('(SUM(CAST(EXTRACT(EPOCH FROM end_at) AS integer)) - SUM(CAST(EXTRACT(EPOCH FROM start_at) AS integer))) / COUNT(visits) AS avg_time_spent')
这是“有效的”方法,但它仅给我每次访问的秒数差异,而不是所有访问的平均值。假设我有4次造访,其中2次造访2小时,1次造访4小时,1次造访1小时;总共9个小时。 avg_time_spent
应该为2.25小时。感谢您提供的任何帮助。
UNION ALL
,GROUPING SETS
的子查询无济于事答案 0 :(得分:1)
根据您来自哪个方面,可以通过以下方式进行操作:
Visit
.group(:user_id, :building_id)
.pluck(:user_id, :building_id, 'AVG("visits"."end_at" - "visits"."start_at")')
.map { |*ids, visit_duration| [ids, visit_duration] }
.to_h
使用用户和建筑物ID作为键,平均访问时间作为值来生成哈希。
如果您来自单个用户:
user.visits.group(:building_id)
.pluck(:building_id, 'AVG("visits"."end_at" - "visits"."start_at")')
.to_h
或者如果您来自建筑物:
building.visits.group(:user_id)
.pluck(:user_id, 'AVG("visits"."end_at" - "visits"."start_at")')
.to_h
我希望以上内容能给您一些启发。该答案仅适用于ID,以保持查询简单。如果要将整个实例设置为键,则可以使用单独的查询来查找它们。
例如:
average_time = user.visits # ...
buildings = average_time.keys.zip(Building.find(average_time.keys)).to_h
average_time.transform_keys! { |building_id| buildings[building_id] }
# The simpler approach
#
# average_time.transform_keys!(&:Building.method(:find))
#
# results in a 1+N query
答案 1 :(得分:0)
您可以尝试使用postgres的平均函数AVG
:
averaged = user.visits.select("AVG(end_at - start_at) as average_interval, building_id").group(:building_id).preload(:building)
averaged.map{|o| [o.building, o.average_interval]}