我有以下'距离'表:
╔════╦════════════╦════════════╦═════════════════╦═════════════════╦══════════╗
║ 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 ║
╚════╩════════════╩════════════╩═════════════════╩═════════════════╩══════════╝
问题是,如何在必要时使用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));
我试过这个,但它不起作用:
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]])
它产生了这个:
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
'))
并提出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)
我是否需要使用简单的SQL? :/
答案 0 :(得分:2)
我想我最好的拍摄是建立"其中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
并称之为:
Distance.distance_matrix([[1.234567, 2.345678], [5.678901, 6.789012]], [[3.456789, 4.567890], [7.890123, 8.901234]])
它有效:D
感谢@BradWerth让我走上正轨,并感谢@muistooshort使代码更具可读性。
答案 1 :(得分:1)
我猜它必须更像这样:
Element.where(&#39;(origin_lat,origin_lng)IN((?,?),(?,?))AND(destination_lat,destination_lng)IN((?,?),(?,?)) &#39;,1.234567,2.345678,5,678901,6.789012,3.456789,4.567890,7.890123,8.901234)