如何按计数和地点组合postgres组

时间:2015-02-06 08:08:42

标签: ruby-on-rails postgresql rails-geocoder ruby-on-rails-4.2

使用Rails 4.2和Postgres我创建了以下查询,根据每只鸟的目击数量,在瞄准表中为我提供了一个uniq的鸟ids列表。另请注意,我正在使用Kaminari宝石进行分页。

 Sighting.select("bird_id, COUNT(sightings.id) as sightings_count").group(:bird_id).order('sightings_count DESC').page(1)

这很有效,可以返回ActiveRecordRelation。当我尝试将它与地理编码器gems .near方法

组合时,问题就出现了
Sighting.near([-31.0, 151.0], 1000, units: :km).select("bird_id, COUNT(sightings.id) as sightings_count").group(:bird_id).order('sightings_count DESC').page(1)

这会生成查询和错误

SELECT  sightings.*, 6371.0 * 2 * ASIN(SQRT(POWER(SIN((-31.0 - sightings.lat) * PI() / 180 / 2), 2) + COS(-31.0 * PI() / 180) * COS(sightings.lat * PI() / 180) * POWER(SIN((151.0 - sightings.lng) * PI() / 180 / 2), 2))) AS distance, MOD(CAST((ATAN2( ((sightings.lng - 151.0) / 57.2957795), ((sightings.lat - -31.0) / 57.2957795)) * 57.2957795) + 360 AS decimal), 360) AS bearing, bird_id, COUNT(sightings.id) as sightings_count FROM "sightings" WHERE (sightings.lat BETWEEN -39.993216059187304 AND -22.006783940812696 AND sightings.lng BETWEEN 140.50821379697885 AND 161.49178620302115 AND (6371.0 * 2 * ASIN(SQRT(POWER(SIN((-31.0 - sightings.lat) * PI() / 180 / 2), 2) + COS(-31.0 * PI() / 180) * COS(sightings.lat * PI() / 180) * POWER(SIN((151.0 - sightings.lng) * PI() / 180 / 2), 2)))) BETWEEN 0.0 AND 1000) GROUP BY bird_id  ORDER BY distance ASC, sightings_count DESC LIMIT 25 OFFSET 0

PG :: GroupingError:错误:列“sightings.id”必须出现在GROUP BY子句中或用于聚合函数

通过鸟类计数不正确将ID添加到组中,据我所知,select中的COUNT是一个聚合函数,其中包含sightings.id。

我如何才能成功地将两者合并?

注意:我确实尝试了以下操作,但这会返回Hash而不是AR Relation。

Sighting.near([@lat, @lng], @range, units: :km, order:nil).group(:bird_id).order('count_id DESC').page(@page).count(:id)

感谢您的帮助!!

1 个答案:

答案 0 :(得分:1)

创建自定义近距离范围是最简单的解决方法,因为我没有使用添加到每个记录的轴承或距离属性,因此我附近生成的整个选择sql不需要。我没有选择(选项[:选择])而是用我想要的选择替换它。

scope :birds_by_sighting, lambda{ |location, *args|
latitude, longitude = Geocoder::Calculations.extract_coordinates(location)
if Geocoder::Calculations.coordinates_present?(latitude, longitude)
  options = near_scope_options(latitude, longitude, *args)
  select("bird_id, COUNT(sightings.id) as sightings_count").group(:bird_id).where(options[:conditions]).order('sightings_count DESC')
else
  # If no lat/lon given we don't want any results, but we still
  # need distance and bearing columns so you can add, for example:
  # .order("distance")
  select(select_clause(nil, null_value, null_value)).where(false_condition)
end
}