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

Posted

技术标签:

【中文标题】Postgres / Rails Active Record - 查询四舍五入的浮点值【英文标题】:Postgres / Rails Active Record -- query for rounded float value 【发布时间】:2014-11-13 23:42:16 【问题描述】:

我在 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)")

希望在数据库中找到纬度值为 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】:

错误是因为没有round 的形式将两个numerics 作为参数。它需要一个numeric 和一个int,其中int 是要四舍五入的位置数。

那么,试试这个:

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

这里是relevant doc(搜索round)。

还请注意,我稍微调整了表达式的右侧。鉴于您正在寻找 30.6703649,四舍五入到小数点后5位,即30.67036,因为下一位是4,表示要向下舍入。

另外,关于您的第一组数字,要使 71.233434 被视为等于 71.233545,您需要四舍五入到小数点后第三位并检查 71.233

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

【讨论】:

非常感谢!那钉了它。作为记录,我还必须将 lat/lon 值(即 DP 值)转换为 Numerics。我已将最终结果放在上面的问题中。 您正在比较 DB 的四舍五入到 1/10 的幂和 ruby​​ 的四舍五入到 1/10 的幂。我怀疑有时可能会以不同的方式舍入相同的值,特别是因为 1/10 的幂在二进制浮点中没有精确表示!我会尝试像ROUND(lat, 5) = ROUND(?, 5) 这样的方法来做同样的事情(未经测试)。

以上是关于Postgres / Rails Active Record - 查询四舍五入的浮点值的主要内容,如果未能解决你的问题,请参考以下文章

Rails 和 Postgres:迁移到 change_colomn 时出现错误“无法强制转换为没有时区的时间戳”

如何在 Rails 迁移中添加检查约束?

Rails中的枚举:大写还是小写?

Rails 4 session.id 偶尔为零

rails - postgres 或 rails 是不是自动验证 datetime 列只能具有 datetime 对象?

如何删除rails的postgres用户密码?