Postgres / Rails Active Record - 查询舍入浮点值

时间:2014-11-13 23:42:16

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

我在Rails应用程序中使用Postgres。将Lat / Lon存储在数据库中作为浮点值。我希望能够比较位置的纬度/经度,但我只知道如何做到完全相等:

Location.where(lat: @lat, lon: @lon)

我的问题是,我希望Postgres阅读,比如71.233434等于71.233545,或者其他什么。换句话说,我可以查询舍入等式或范围内的相等吗?

我已经在谷歌搜索了这个相当广泛的(可能使用了错误的术语?我想不到它。“Active Record Postgres漂浮在”,“Active Record Postgres舍入查询”等)。但是没有运气。我只找到了如何round values coming out of the database,这没有多大帮助,因为在Ruby中很容易做到。

有什么想法吗?我更喜欢某种Active Record解决方案,如果它存在,但如果没有,我也非常感谢(链接)实际的查询代码。

谢谢!

编辑 - 查看this answer,我尝试了以下内容:

Location.find_by_sql("SELECT * FROM locations WHERE lat = ROUND(30.67035, 0.001)")

希望在数据库中找到lat值为30.6703649的位置,但我遇到了这个错误:

ActiveRecord::StatementInvalid: PG::UndefinedFunction: ERROR:  function round(numeric, numeric) does not exist
LINE 1: SELECT * FROM places WHERE lat = ROUND(30.67035, 0.001)

当我尝试相反时基本相同的错误,这更有意义:

Location.find_by_sql("SELECT * FROM locations WHERE ROUND(lat, 0,001) = 30.67035")

我的回答基于以下回复:

  scope :none, -> { where('1=2') } # returns an empty relation
  scope :by_ll, -> (lat, lon) { by_lat(lat).by_lon(lon) }
  scope :by_lat, -> (lat) { lat ? where("ROUND( CAST(lat as numeric), 4 ) = ?", lat.round(4) ) : none }
  scope :by_lon, -> (lon) { lon ? where("ROUND( CAST(lon as numeric), 4 ) = ?", lon.round(4) ) : none }

1 个答案:

答案 0 :(得分:4)

错误是因为没有round的形式,它将两个numeric作为参数。它需要numericint,其中int是要舍入的地方数。

所以,试试这个:

Location.find_by_sql("SELECT * FROM locations WHERE ROUND(lat, 5) = 30.67036")

以下是relevant doc(搜索round)。

另请注意,我略微调整了表达式的右侧。鉴于你在寻找 30.6703649,舍入到小数点后第五位,即30.67036,因为下一个数字是4,表示它将向下舍入。

此外,关于您的第一组数字,要使71.233434等于71.233545,您需要舍入到小数点后第3位并检查71.233。< / p>

我建议您确定要在值中支持的容差 - 即小数点后三位或第五位 - 然后在调用round时使用该参数。