Fel*_*van 5 ruby sql postgresql activerecord ruby-on-rails
我有以下'距离'表:
???????????????????????????????????????????????????????????????????????????????
? id ? origin_lat ? origin_lng ? destination_lat ? destination_lng ? distance ?
???????????????????????????????????????????????????????????????????????????????
? 1 ? 1.234567 ? 2.345678 ? 3.456789 ? 4.567890 ? 10 ?
? 2 ? 5.678901 ? 6.789012 ? 7.890123 ? 8.901234 ? 20 ?
???????????????????????????????????????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)
问题是,如何在必要时使用ActiveRecord和Arel创建以下SQL查询(由PostgreSQL支持):
SELECT *
FROM distances
WHERE
(origin_lat, origin_lng) IN ((1.234567, 2.345678), (5.678901, 6.789012))
AND
(destination_lat, destination_lng) IN ((3.456789, 4.567890), (7.890123, 8.901234));
Run Code Online (Sandbox Code Playgroud)
我试过这个,但它不起作用:
Distance.where('(origin_lat, origin_lng) IN (?) AND (destination_lat, destination_lng) IN (?)', [[1.234567, 2.345678], [5.678901, 6.789012]], [[3.456789, 4.567890], [7.890123, 8.901234]])
Run Code Online (Sandbox Code Playgroud)
它产生了这个:
SELECT "distances".* FROM "distances" WHERE ((origin_lat, origin_lng) IN ('---
- 1.234567
- 2.345678
','---
- 5.678901
- 6.789012
') AND (destination_lat, destination_lng) IN ('---
- 3.456789
- 4.56789
','---
- 7.890123
- 8.901234
'))
Run Code Online (Sandbox Code Playgroud)
并加注 PG::FeatureNotSupported: ERROR: input of anonymous composite types is not implemented
参数的数量是可变的,所以我不能像这样对查询进行硬编码:
Distance.where('(origin_lat, origin_lng) IN ((?,?),(?,?)) AND (destination_lat, destination_lng) IN ((?,?),(?,?))', 1.234567, 2.345678, 5.678901, 6.789012, 3.456789, 4.567890, 7.890123, 8.901234)
Run Code Online (Sandbox Code Playgroud)
我是否需要使用简单的SQL?:/
我想我最好的办法是自己构建“where SQL”字符串,展平并展开参数,所以我创建了这个方法:
class Distance < ActiveRecord::Base
def self.distance_matrix(origins, destinations)
return false if origins.empty? || destinations.empty?
where_sql = '(origin_lat, origin_lng) IN ('
where_sql << (['(?, ?)'] * origins.length).join(', ')
where_sql << ') AND (destination_lat, destination_lng) IN ('
where_sql << (['(?, ?)'] * destinations.length).join(', ') << ')'
where(where_sql, *origins.flatten, *destinations.flatten)
end
end
Run Code Online (Sandbox Code Playgroud)
并这样称呼它:
Distance.distance_matrix([[1.234567, 2.345678], [5.678901, 6.789012]], [[3.456789, 4.567890], [7.890123, 8.901234]])
Run Code Online (Sandbox Code Playgroud)
它有效:D
感谢@BradWerth 让我走上正轨,感谢@muistooshort 让代码更具可读性。
| 归档时间: |
|
| 查看次数: |
265 次 |
| 最近记录: |